diff options
author | Christian König <deathsimple@vodafone.de> | 2013-04-08 06:41:29 -0400 |
---|---|---|
committer | Alex Deucher <alexander.deucher@amd.com> | 2013-04-09 10:31:33 -0400 |
commit | f2ba57b5eab8817d86d0f108fdf1878e51dc0a37 (patch) | |
tree | e784f0573069f6341768968fe3d49df6d2c9a534 | |
parent | 4474f3a91f95e3fcc62d97e36f1e8e3392c96ee0 (diff) |
drm/radeon: UVD bringup v8
Just everything needed to decode videos using UVD.
v6: just all the bugfixes and support for R7xx-SI merged in one patch
v7: UVD_CGC_GATE is a write only register, lockup detection fix
v8: split out VRAM fallback changes, remove support for RV770,
add support for HEMLOCK, add buffer sizes checks
Signed-off-by: Christian König <christian.koenig@amd.com>
Reviewed-by: Jerome Glisse <jglisse@redhat.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
23 files changed, 1534 insertions, 53 deletions
diff --git a/drivers/gpu/drm/radeon/Makefile b/drivers/gpu/drm/radeon/Makefile index bf172522ea68..86c5e3611892 100644 --- a/drivers/gpu/drm/radeon/Makefile +++ b/drivers/gpu/drm/radeon/Makefile | |||
@@ -76,7 +76,7 @@ radeon-y += radeon_device.o radeon_asic.o radeon_kms.o \ | |||
76 | evergreen.o evergreen_cs.o evergreen_blit_shaders.o evergreen_blit_kms.o \ | 76 | evergreen.o evergreen_cs.o evergreen_blit_shaders.o evergreen_blit_kms.o \ |
77 | evergreen_hdmi.o radeon_trace_points.o ni.o cayman_blit_shaders.o \ | 77 | evergreen_hdmi.o radeon_trace_points.o ni.o cayman_blit_shaders.o \ |
78 | atombios_encoders.o radeon_semaphore.o radeon_sa.o atombios_i2c.o si.o \ | 78 | atombios_encoders.o radeon_semaphore.o radeon_sa.o atombios_i2c.o si.o \ |
79 | si_blit_shaders.o radeon_prime.o | 79 | si_blit_shaders.o radeon_prime.o radeon_uvd.o |
80 | 80 | ||
81 | radeon-$(CONFIG_COMPAT) += radeon_ioc32.o | 81 | radeon-$(CONFIG_COMPAT) += radeon_ioc32.o |
82 | radeon-$(CONFIG_VGA_SWITCHEROO) += radeon_atpx_handler.o | 82 | radeon-$(CONFIG_VGA_SWITCHEROO) += radeon_atpx_handler.o |
diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index 305a657bf215..18b66ff59dcf 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c | |||
@@ -3360,6 +3360,9 @@ restart_ih: | |||
3360 | DRM_ERROR("Unhandled interrupt: %d %d\n", src_id, src_data); | 3360 | DRM_ERROR("Unhandled interrupt: %d %d\n", src_id, src_data); |
3361 | break; | 3361 | break; |
3362 | } | 3362 | } |
3363 | case 124: /* UVD */ | ||
3364 | DRM_DEBUG("IH: UVD int: 0x%08x\n", src_data); | ||
3365 | radeon_fence_process(rdev, R600_RING_TYPE_UVD_INDEX); | ||
3363 | break; | 3366 | break; |
3364 | case 146: | 3367 | case 146: |
3365 | case 147: | 3368 | case 147: |
@@ -3571,7 +3574,7 @@ int evergreen_copy_dma(struct radeon_device *rdev, | |||
3571 | 3574 | ||
3572 | static int evergreen_startup(struct radeon_device *rdev) | 3575 | static int evergreen_startup(struct radeon_device *rdev) |
3573 | { | 3576 | { |
3574 | struct radeon_ring *ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]; | 3577 | struct radeon_ring *ring; |
3575 | int r; | 3578 | int r; |
3576 | 3579 | ||
3577 | /* enable pcie gen2 link */ | 3580 | /* enable pcie gen2 link */ |
@@ -3638,6 +3641,17 @@ static int evergreen_startup(struct radeon_device *rdev) | |||
3638 | return r; | 3641 | return r; |
3639 | } | 3642 | } |
3640 | 3643 | ||
3644 | r = rv770_uvd_resume(rdev); | ||
3645 | if (!r) { | ||
3646 | r = radeon_fence_driver_start_ring(rdev, | ||
3647 | R600_RING_TYPE_UVD_INDEX); | ||
3648 | if (r) | ||
3649 | dev_err(rdev->dev, "UVD fences init error (%d).\n", r); | ||
3650 | } | ||
3651 | |||
3652 | if (r) | ||
3653 | rdev->ring[R600_RING_TYPE_UVD_INDEX].ring_size = 0; | ||
3654 | |||
3641 | /* Enable IRQ */ | 3655 | /* Enable IRQ */ |
3642 | r = r600_irq_init(rdev); | 3656 | r = r600_irq_init(rdev); |
3643 | if (r) { | 3657 | if (r) { |
@@ -3647,6 +3661,7 @@ static int evergreen_startup(struct radeon_device *rdev) | |||
3647 | } | 3661 | } |
3648 | evergreen_irq_set(rdev); | 3662 | evergreen_irq_set(rdev); |
3649 | 3663 | ||
3664 | ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]; | ||
3650 | r = radeon_ring_init(rdev, ring, ring->ring_size, RADEON_WB_CP_RPTR_OFFSET, | 3665 | r = radeon_ring_init(rdev, ring, ring->ring_size, RADEON_WB_CP_RPTR_OFFSET, |
3651 | R600_CP_RB_RPTR, R600_CP_RB_WPTR, | 3666 | R600_CP_RB_RPTR, R600_CP_RB_WPTR, |
3652 | 0, 0xfffff, RADEON_CP_PACKET2); | 3667 | 0, 0xfffff, RADEON_CP_PACKET2); |
@@ -3670,6 +3685,19 @@ static int evergreen_startup(struct radeon_device *rdev) | |||
3670 | if (r) | 3685 | if (r) |
3671 | return r; | 3686 | return r; |
3672 | 3687 | ||
3688 | ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX]; | ||
3689 | if (ring->ring_size) { | ||
3690 | r = radeon_ring_init(rdev, ring, ring->ring_size, | ||
3691 | R600_WB_UVD_RPTR_OFFSET, | ||
3692 | UVD_RBC_RB_RPTR, UVD_RBC_RB_WPTR, | ||
3693 | 0, 0xfffff, RADEON_CP_PACKET2); | ||
3694 | if (!r) | ||
3695 | r = r600_uvd_init(rdev); | ||
3696 | |||
3697 | if (r) | ||
3698 | DRM_ERROR("radeon: error initializing UVD (%d).\n", r); | ||
3699 | } | ||
3700 | |||
3673 | r = radeon_ib_pool_init(rdev); | 3701 | r = radeon_ib_pool_init(rdev); |
3674 | if (r) { | 3702 | if (r) { |
3675 | dev_err(rdev->dev, "IB initialization failed (%d).\n", r); | 3703 | dev_err(rdev->dev, "IB initialization failed (%d).\n", r); |
@@ -3716,8 +3744,10 @@ int evergreen_resume(struct radeon_device *rdev) | |||
3716 | int evergreen_suspend(struct radeon_device *rdev) | 3744 | int evergreen_suspend(struct radeon_device *rdev) |
3717 | { | 3745 | { |
3718 | r600_audio_fini(rdev); | 3746 | r600_audio_fini(rdev); |
3747 | radeon_uvd_suspend(rdev); | ||
3719 | r700_cp_stop(rdev); | 3748 | r700_cp_stop(rdev); |
3720 | r600_dma_stop(rdev); | 3749 | r600_dma_stop(rdev); |
3750 | r600_uvd_rbc_stop(rdev); | ||
3721 | evergreen_irq_suspend(rdev); | 3751 | evergreen_irq_suspend(rdev); |
3722 | radeon_wb_disable(rdev); | 3752 | radeon_wb_disable(rdev); |
3723 | evergreen_pcie_gart_disable(rdev); | 3753 | evergreen_pcie_gart_disable(rdev); |
@@ -3797,6 +3827,13 @@ int evergreen_init(struct radeon_device *rdev) | |||
3797 | rdev->ring[R600_RING_TYPE_DMA_INDEX].ring_obj = NULL; | 3827 | rdev->ring[R600_RING_TYPE_DMA_INDEX].ring_obj = NULL; |
3798 | r600_ring_init(rdev, &rdev->ring[R600_RING_TYPE_DMA_INDEX], 64 * 1024); | 3828 | r600_ring_init(rdev, &rdev->ring[R600_RING_TYPE_DMA_INDEX], 64 * 1024); |
3799 | 3829 | ||
3830 | r = radeon_uvd_init(rdev); | ||
3831 | if (!r) { | ||
3832 | rdev->ring[R600_RING_TYPE_UVD_INDEX].ring_obj = NULL; | ||
3833 | r600_ring_init(rdev, &rdev->ring[R600_RING_TYPE_UVD_INDEX], | ||
3834 | 4096); | ||
3835 | } | ||
3836 | |||
3800 | rdev->ih.ring_obj = NULL; | 3837 | rdev->ih.ring_obj = NULL; |
3801 | r600_ih_ring_init(rdev, 64 * 1024); | 3838 | r600_ih_ring_init(rdev, 64 * 1024); |
3802 | 3839 | ||
@@ -3843,6 +3880,7 @@ void evergreen_fini(struct radeon_device *rdev) | |||
3843 | radeon_ib_pool_fini(rdev); | 3880 | radeon_ib_pool_fini(rdev); |
3844 | radeon_irq_kms_fini(rdev); | 3881 | radeon_irq_kms_fini(rdev); |
3845 | evergreen_pcie_gart_fini(rdev); | 3882 | evergreen_pcie_gart_fini(rdev); |
3883 | radeon_uvd_fini(rdev); | ||
3846 | r600_vram_scratch_fini(rdev); | 3884 | r600_vram_scratch_fini(rdev); |
3847 | radeon_gem_fini(rdev); | 3885 | radeon_gem_fini(rdev); |
3848 | radeon_fence_driver_fini(rdev); | 3886 | radeon_fence_driver_fini(rdev); |
diff --git a/drivers/gpu/drm/radeon/evergreend.h b/drivers/gpu/drm/radeon/evergreend.h index 982d25ad9af3..c5d873e525c9 100644 --- a/drivers/gpu/drm/radeon/evergreend.h +++ b/drivers/gpu/drm/radeon/evergreend.h | |||
@@ -992,6 +992,13 @@ | |||
992 | # define TARGET_LINK_SPEED_MASK (0xf << 0) | 992 | # define TARGET_LINK_SPEED_MASK (0xf << 0) |
993 | # define SELECTABLE_DEEMPHASIS (1 << 6) | 993 | # define SELECTABLE_DEEMPHASIS (1 << 6) |
994 | 994 | ||
995 | |||
996 | /* | ||
997 | * UVD | ||
998 | */ | ||
999 | #define UVD_RBC_RB_RPTR 0xf690 | ||
1000 | #define UVD_RBC_RB_WPTR 0xf694 | ||
1001 | |||
995 | /* | 1002 | /* |
996 | * PM4 | 1003 | * PM4 |
997 | */ | 1004 | */ |
diff --git a/drivers/gpu/drm/radeon/ni.c b/drivers/gpu/drm/radeon/ni.c index 02e958063682..35d7caa60c48 100644 --- a/drivers/gpu/drm/radeon/ni.c +++ b/drivers/gpu/drm/radeon/ni.c | |||
@@ -933,6 +933,23 @@ void cayman_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib) | |||
933 | radeon_ring_write(ring, 10); /* poll interval */ | 933 | radeon_ring_write(ring, 10); /* poll interval */ |
934 | } | 934 | } |
935 | 935 | ||
936 | void cayman_uvd_semaphore_emit(struct radeon_device *rdev, | ||
937 | struct radeon_ring *ring, | ||
938 | struct radeon_semaphore *semaphore, | ||
939 | bool emit_wait) | ||
940 | { | ||
941 | uint64_t addr = semaphore->gpu_addr; | ||
942 | |||
943 | radeon_ring_write(ring, PACKET0(UVD_SEMA_ADDR_LOW, 0)); | ||
944 | radeon_ring_write(ring, (addr >> 3) & 0x000FFFFF); | ||
945 | |||
946 | radeon_ring_write(ring, PACKET0(UVD_SEMA_ADDR_HIGH, 0)); | ||
947 | radeon_ring_write(ring, (addr >> 23) & 0x000FFFFF); | ||
948 | |||
949 | radeon_ring_write(ring, PACKET0(UVD_SEMA_CMD, 0)); | ||
950 | radeon_ring_write(ring, 0x80 | (emit_wait ? 1 : 0)); | ||
951 | } | ||
952 | |||
936 | static void cayman_cp_enable(struct radeon_device *rdev, bool enable) | 953 | static void cayman_cp_enable(struct radeon_device *rdev, bool enable) |
937 | { | 954 | { |
938 | if (enable) | 955 | if (enable) |
@@ -1684,6 +1701,16 @@ static int cayman_startup(struct radeon_device *rdev) | |||
1684 | return r; | 1701 | return r; |
1685 | } | 1702 | } |
1686 | 1703 | ||
1704 | r = rv770_uvd_resume(rdev); | ||
1705 | if (!r) { | ||
1706 | r = radeon_fence_driver_start_ring(rdev, | ||
1707 | R600_RING_TYPE_UVD_INDEX); | ||
1708 | if (r) | ||
1709 | dev_err(rdev->dev, "UVD fences init error (%d).\n", r); | ||
1710 | } | ||
1711 | if (r) | ||
1712 | rdev->ring[R600_RING_TYPE_UVD_INDEX].ring_size = 0; | ||
1713 | |||
1687 | r = radeon_fence_driver_start_ring(rdev, CAYMAN_RING_TYPE_CP1_INDEX); | 1714 | r = radeon_fence_driver_start_ring(rdev, CAYMAN_RING_TYPE_CP1_INDEX); |
1688 | if (r) { | 1715 | if (r) { |
1689 | dev_err(rdev->dev, "failed initializing CP fences (%d).\n", r); | 1716 | dev_err(rdev->dev, "failed initializing CP fences (%d).\n", r); |
@@ -1750,6 +1777,18 @@ static int cayman_startup(struct radeon_device *rdev) | |||
1750 | if (r) | 1777 | if (r) |
1751 | return r; | 1778 | return r; |
1752 | 1779 | ||
1780 | ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX]; | ||
1781 | if (ring->ring_size) { | ||
1782 | r = radeon_ring_init(rdev, ring, ring->ring_size, | ||
1783 | R600_WB_UVD_RPTR_OFFSET, | ||
1784 | UVD_RBC_RB_RPTR, UVD_RBC_RB_WPTR, | ||
1785 | 0, 0xfffff, RADEON_CP_PACKET2); | ||
1786 | if (!r) | ||
1787 | r = r600_uvd_init(rdev); | ||
1788 | if (r) | ||
1789 | DRM_ERROR("radeon: failed initializing UVD (%d).\n", r); | ||
1790 | } | ||
1791 | |||
1753 | r = radeon_ib_pool_init(rdev); | 1792 | r = radeon_ib_pool_init(rdev); |
1754 | if (r) { | 1793 | if (r) { |
1755 | dev_err(rdev->dev, "IB initialization failed (%d).\n", r); | 1794 | dev_err(rdev->dev, "IB initialization failed (%d).\n", r); |
@@ -1796,6 +1835,8 @@ int cayman_suspend(struct radeon_device *rdev) | |||
1796 | radeon_vm_manager_fini(rdev); | 1835 | radeon_vm_manager_fini(rdev); |
1797 | cayman_cp_enable(rdev, false); | 1836 | cayman_cp_enable(rdev, false); |
1798 | cayman_dma_stop(rdev); | 1837 | cayman_dma_stop(rdev); |
1838 | r600_uvd_rbc_stop(rdev); | ||
1839 | radeon_uvd_suspend(rdev); | ||
1799 | evergreen_irq_suspend(rdev); | 1840 | evergreen_irq_suspend(rdev); |
1800 | radeon_wb_disable(rdev); | 1841 | radeon_wb_disable(rdev); |
1801 | cayman_pcie_gart_disable(rdev); | 1842 | cayman_pcie_gart_disable(rdev); |
@@ -1870,6 +1911,13 @@ int cayman_init(struct radeon_device *rdev) | |||
1870 | ring->ring_obj = NULL; | 1911 | ring->ring_obj = NULL; |
1871 | r600_ring_init(rdev, ring, 64 * 1024); | 1912 | r600_ring_init(rdev, ring, 64 * 1024); |
1872 | 1913 | ||
1914 | r = radeon_uvd_init(rdev); | ||
1915 | if (!r) { | ||
1916 | ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX]; | ||
1917 | ring->ring_obj = NULL; | ||
1918 | r600_ring_init(rdev, ring, 4096); | ||
1919 | } | ||
1920 | |||
1873 | rdev->ih.ring_obj = NULL; | 1921 | rdev->ih.ring_obj = NULL; |
1874 | r600_ih_ring_init(rdev, 64 * 1024); | 1922 | r600_ih_ring_init(rdev, 64 * 1024); |
1875 | 1923 | ||
@@ -1921,6 +1969,7 @@ void cayman_fini(struct radeon_device *rdev) | |||
1921 | radeon_vm_manager_fini(rdev); | 1969 | radeon_vm_manager_fini(rdev); |
1922 | radeon_ib_pool_fini(rdev); | 1970 | radeon_ib_pool_fini(rdev); |
1923 | radeon_irq_kms_fini(rdev); | 1971 | radeon_irq_kms_fini(rdev); |
1972 | radeon_uvd_fini(rdev); | ||
1924 | cayman_pcie_gart_fini(rdev); | 1973 | cayman_pcie_gart_fini(rdev); |
1925 | r600_vram_scratch_fini(rdev); | 1974 | r600_vram_scratch_fini(rdev); |
1926 | radeon_gem_fini(rdev); | 1975 | radeon_gem_fini(rdev); |
diff --git a/drivers/gpu/drm/radeon/nid.h b/drivers/gpu/drm/radeon/nid.h index 445b235c4323..f2555bc44ada 100644 --- a/drivers/gpu/drm/radeon/nid.h +++ b/drivers/gpu/drm/radeon/nid.h | |||
@@ -490,6 +490,15 @@ | |||
490 | # define CACHE_FLUSH_AND_INV_EVENT (0x16 << 0) | 490 | # define CACHE_FLUSH_AND_INV_EVENT (0x16 << 0) |
491 | 491 | ||
492 | /* | 492 | /* |
493 | * UVD | ||
494 | */ | ||
495 | #define UVD_SEMA_ADDR_LOW 0xEF00 | ||
496 | #define UVD_SEMA_ADDR_HIGH 0xEF04 | ||
497 | #define UVD_SEMA_CMD 0xEF08 | ||
498 | #define UVD_RBC_RB_RPTR 0xF690 | ||
499 | #define UVD_RBC_RB_WPTR 0xF694 | ||
500 | |||
501 | /* | ||
493 | * PM4 | 502 | * PM4 |
494 | */ | 503 | */ |
495 | #define PACKET0(reg, n) ((RADEON_PACKET_TYPE0 << 30) | \ | 504 | #define PACKET0(reg, n) ((RADEON_PACKET_TYPE0 << 30) | \ |
diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 1c5308778948..7ce7b83c76f5 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c | |||
@@ -2552,6 +2552,185 @@ void r600_dma_fini(struct radeon_device *rdev) | |||
2552 | } | 2552 | } |
2553 | 2553 | ||
2554 | /* | 2554 | /* |
2555 | * UVD | ||
2556 | */ | ||
2557 | int r600_uvd_rbc_start(struct radeon_device *rdev) | ||
2558 | { | ||
2559 | struct radeon_ring *ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX]; | ||
2560 | uint64_t rptr_addr; | ||
2561 | uint32_t rb_bufsz, tmp; | ||
2562 | int r; | ||
2563 | |||
2564 | rptr_addr = rdev->wb.gpu_addr + R600_WB_UVD_RPTR_OFFSET; | ||
2565 | |||
2566 | if (upper_32_bits(rptr_addr) != upper_32_bits(ring->gpu_addr)) { | ||
2567 | DRM_ERROR("UVD ring and rptr not in the same 4GB segment!\n"); | ||
2568 | return -EINVAL; | ||
2569 | } | ||
2570 | |||
2571 | /* force RBC into idle state */ | ||
2572 | WREG32(UVD_RBC_RB_CNTL, 0x11010101); | ||
2573 | |||
2574 | /* Set the write pointer delay */ | ||
2575 | WREG32(UVD_RBC_RB_WPTR_CNTL, 0); | ||
2576 | |||
2577 | /* set the wb address */ | ||
2578 | WREG32(UVD_RBC_RB_RPTR_ADDR, rptr_addr >> 2); | ||
2579 | |||
2580 | /* programm the 4GB memory segment for rptr and ring buffer */ | ||
2581 | WREG32(UVD_LMI_EXT40_ADDR, upper_32_bits(rptr_addr) | | ||
2582 | (0x7 << 16) | (0x1 << 31)); | ||
2583 | |||
2584 | /* Initialize the ring buffer's read and write pointers */ | ||
2585 | WREG32(UVD_RBC_RB_RPTR, 0x0); | ||
2586 | |||
2587 | ring->wptr = ring->rptr = RREG32(UVD_RBC_RB_RPTR); | ||
2588 | WREG32(UVD_RBC_RB_WPTR, ring->wptr); | ||
2589 | |||
2590 | /* set the ring address */ | ||
2591 | WREG32(UVD_RBC_RB_BASE, ring->gpu_addr); | ||
2592 | |||
2593 | /* Set ring buffer size */ | ||
2594 | rb_bufsz = drm_order(ring->ring_size); | ||
2595 | rb_bufsz = (0x1 << 8) | rb_bufsz; | ||
2596 | WREG32(UVD_RBC_RB_CNTL, rb_bufsz); | ||
2597 | |||
2598 | ring->ready = true; | ||
2599 | r = radeon_ring_test(rdev, R600_RING_TYPE_UVD_INDEX, ring); | ||
2600 | if (r) { | ||
2601 | ring->ready = false; | ||
2602 | return r; | ||
2603 | } | ||
2604 | |||
2605 | r = radeon_ring_lock(rdev, ring, 10); | ||
2606 | if (r) { | ||
2607 | DRM_ERROR("radeon: ring failed to lock UVD ring (%d).\n", r); | ||
2608 | return r; | ||
2609 | } | ||
2610 | |||
2611 | tmp = PACKET0(UVD_SEMA_WAIT_FAULT_TIMEOUT_CNTL, 0); | ||
2612 | radeon_ring_write(ring, tmp); | ||
2613 | radeon_ring_write(ring, 0xFFFFF); | ||
2614 | |||
2615 | tmp = PACKET0(UVD_SEMA_WAIT_INCOMPLETE_TIMEOUT_CNTL, 0); | ||
2616 | radeon_ring_write(ring, tmp); | ||
2617 | radeon_ring_write(ring, 0xFFFFF); | ||
2618 | |||
2619 | tmp = PACKET0(UVD_SEMA_SIGNAL_INCOMPLETE_TIMEOUT_CNTL, 0); | ||
2620 | radeon_ring_write(ring, tmp); | ||
2621 | radeon_ring_write(ring, 0xFFFFF); | ||
2622 | |||
2623 | /* Clear timeout status bits */ | ||
2624 | radeon_ring_write(ring, PACKET0(UVD_SEMA_TIMEOUT_STATUS, 0)); | ||
2625 | radeon_ring_write(ring, 0x8); | ||
2626 | |||
2627 | radeon_ring_write(ring, PACKET0(UVD_SEMA_CNTL, 0)); | ||
2628 | radeon_ring_write(ring, 1); | ||
2629 | |||
2630 | radeon_ring_unlock_commit(rdev, ring); | ||
2631 | |||
2632 | return 0; | ||
2633 | } | ||
2634 | |||
2635 | void r600_uvd_rbc_stop(struct radeon_device *rdev) | ||
2636 | { | ||
2637 | struct radeon_ring *ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX]; | ||
2638 | |||
2639 | /* force RBC into idle state */ | ||
2640 | WREG32(UVD_RBC_RB_CNTL, 0x11010101); | ||
2641 | ring->ready = false; | ||
2642 | } | ||
2643 | |||
2644 | int r600_uvd_init(struct radeon_device *rdev) | ||
2645 | { | ||
2646 | int i, j, r; | ||
2647 | |||
2648 | /* disable clock gating */ | ||
2649 | WREG32(UVD_CGC_GATE, 0); | ||
2650 | |||
2651 | /* disable interupt */ | ||
2652 | WREG32_P(UVD_MASTINT_EN, 0, ~(1 << 1)); | ||
2653 | |||
2654 | /* put LMI, VCPU, RBC etc... into reset */ | ||
2655 | WREG32(UVD_SOFT_RESET, LMI_SOFT_RESET | VCPU_SOFT_RESET | | ||
2656 | LBSI_SOFT_RESET | RBC_SOFT_RESET | CSM_SOFT_RESET | | ||
2657 | CXW_SOFT_RESET | TAP_SOFT_RESET | LMI_UMC_SOFT_RESET); | ||
2658 | mdelay(5); | ||
2659 | |||
2660 | /* take UVD block out of reset */ | ||
2661 | WREG32_P(SRBM_SOFT_RESET, 0, ~SOFT_RESET_UVD); | ||
2662 | mdelay(5); | ||
2663 | |||
2664 | /* initialize UVD memory controller */ | ||
2665 | WREG32(UVD_LMI_CTRL, 0x40 | (1 << 8) | (1 << 13) | | ||
2666 | (1 << 21) | (1 << 9) | (1 << 20)); | ||
2667 | |||
2668 | /* disable byte swapping */ | ||
2669 | WREG32(UVD_LMI_SWAP_CNTL, 0); | ||
2670 | WREG32(UVD_MP_SWAP_CNTL, 0); | ||
2671 | |||
2672 | WREG32(UVD_MPC_SET_MUXA0, 0x40c2040); | ||
2673 | WREG32(UVD_MPC_SET_MUXA1, 0x0); | ||
2674 | WREG32(UVD_MPC_SET_MUXB0, 0x40c2040); | ||
2675 | WREG32(UVD_MPC_SET_MUXB1, 0x0); | ||
2676 | WREG32(UVD_MPC_SET_ALU, 0); | ||
2677 | WREG32(UVD_MPC_SET_MUX, 0x88); | ||
2678 | |||
2679 | /* Stall UMC */ | ||
2680 | WREG32_P(UVD_LMI_CTRL2, 1 << 8, ~(1 << 8)); | ||
2681 | WREG32_P(UVD_RB_ARB_CTRL, 1 << 3, ~(1 << 3)); | ||
2682 | |||
2683 | /* take all subblocks out of reset, except VCPU */ | ||
2684 | WREG32(UVD_SOFT_RESET, VCPU_SOFT_RESET); | ||
2685 | mdelay(5); | ||
2686 | |||
2687 | /* enable VCPU clock */ | ||
2688 | WREG32(UVD_VCPU_CNTL, 1 << 9); | ||
2689 | |||
2690 | /* enable UMC */ | ||
2691 | WREG32_P(UVD_LMI_CTRL2, 0, ~(1 << 8)); | ||
2692 | |||
2693 | /* boot up the VCPU */ | ||
2694 | WREG32(UVD_SOFT_RESET, 0); | ||
2695 | mdelay(10); | ||
2696 | |||
2697 | WREG32_P(UVD_RB_ARB_CTRL, 0, ~(1 << 3)); | ||
2698 | |||
2699 | for (i = 0; i < 10; ++i) { | ||
2700 | uint32_t status; | ||
2701 | for (j = 0; j < 100; ++j) { | ||
2702 | status = RREG32(UVD_STATUS); | ||
2703 | if (status & 2) | ||
2704 | break; | ||
2705 | mdelay(10); | ||
2706 | } | ||
2707 | r = 0; | ||
2708 | if (status & 2) | ||
2709 | break; | ||
2710 | |||
2711 | DRM_ERROR("UVD not responding, trying to reset the VCPU!!!\n"); | ||
2712 | WREG32_P(UVD_SOFT_RESET, VCPU_SOFT_RESET, ~VCPU_SOFT_RESET); | ||
2713 | mdelay(10); | ||
2714 | WREG32_P(UVD_SOFT_RESET, 0, ~VCPU_SOFT_RESET); | ||
2715 | mdelay(10); | ||
2716 | r = -1; | ||
2717 | } | ||
2718 | if (r) { | ||
2719 | DRM_ERROR("UVD not responding, giving up!!!\n"); | ||
2720 | return r; | ||
2721 | } | ||
2722 | /* enable interupt */ | ||
2723 | WREG32_P(UVD_MASTINT_EN, 3<<1, ~(3 << 1)); | ||
2724 | |||
2725 | r = r600_uvd_rbc_start(rdev); | ||
2726 | if (r) | ||
2727 | return r; | ||
2728 | |||
2729 | DRM_INFO("UVD initialized successfully.\n"); | ||
2730 | return 0; | ||
2731 | } | ||
2732 | |||
2733 | /* | ||
2555 | * GPU scratch registers helpers function. | 2734 | * GPU scratch registers helpers function. |
2556 | */ | 2735 | */ |
2557 | void r600_scratch_init(struct radeon_device *rdev) | 2736 | void r600_scratch_init(struct radeon_device *rdev) |
@@ -2660,6 +2839,40 @@ int r600_dma_ring_test(struct radeon_device *rdev, | |||
2660 | return r; | 2839 | return r; |
2661 | } | 2840 | } |
2662 | 2841 | ||
2842 | int r600_uvd_ring_test(struct radeon_device *rdev, struct radeon_ring *ring) | ||
2843 | { | ||
2844 | uint32_t tmp = 0; | ||
2845 | unsigned i; | ||
2846 | int r; | ||
2847 | |||
2848 | WREG32(UVD_CONTEXT_ID, 0xCAFEDEAD); | ||
2849 | r = radeon_ring_lock(rdev, ring, 3); | ||
2850 | if (r) { | ||
2851 | DRM_ERROR("radeon: cp failed to lock ring %d (%d).\n", | ||
2852 | ring->idx, r); | ||
2853 | return r; | ||
2854 | } | ||
2855 | radeon_ring_write(ring, PACKET0(UVD_CONTEXT_ID, 0)); | ||
2856 | radeon_ring_write(ring, 0xDEADBEEF); | ||
2857 | radeon_ring_unlock_commit(rdev, ring); | ||
2858 | for (i = 0; i < rdev->usec_timeout; i++) { | ||
2859 | tmp = RREG32(UVD_CONTEXT_ID); | ||
2860 | if (tmp == 0xDEADBEEF) | ||
2861 | break; | ||
2862 | DRM_UDELAY(1); | ||
2863 | } | ||
2864 | |||
2865 | if (i < rdev->usec_timeout) { | ||
2866 | DRM_INFO("ring test on %d succeeded in %d usecs\n", | ||
2867 | ring->idx, i); | ||
2868 | } else { | ||
2869 | DRM_ERROR("radeon: ring %d test failed (0x%08X)\n", | ||
2870 | ring->idx, tmp); | ||
2871 | r = -EINVAL; | ||
2872 | } | ||
2873 | return r; | ||
2874 | } | ||
2875 | |||
2663 | /* | 2876 | /* |
2664 | * CP fences/semaphores | 2877 | * CP fences/semaphores |
2665 | */ | 2878 | */ |
@@ -2711,6 +2924,30 @@ void r600_fence_ring_emit(struct radeon_device *rdev, | |||
2711 | } | 2924 | } |
2712 | } | 2925 | } |
2713 | 2926 | ||
2927 | void r600_uvd_fence_emit(struct radeon_device *rdev, | ||
2928 | struct radeon_fence *fence) | ||
2929 | { | ||
2930 | struct radeon_ring *ring = &rdev->ring[fence->ring]; | ||
2931 | uint32_t addr = rdev->fence_drv[fence->ring].gpu_addr; | ||
2932 | |||
2933 | radeon_ring_write(ring, PACKET0(UVD_CONTEXT_ID, 0)); | ||
2934 | radeon_ring_write(ring, fence->seq); | ||
2935 | radeon_ring_write(ring, PACKET0(UVD_GPCOM_VCPU_DATA0, 0)); | ||
2936 | radeon_ring_write(ring, addr & 0xffffffff); | ||
2937 | radeon_ring_write(ring, PACKET0(UVD_GPCOM_VCPU_DATA1, 0)); | ||
2938 | radeon_ring_write(ring, upper_32_bits(addr) & 0xff); | ||
2939 | radeon_ring_write(ring, PACKET0(UVD_GPCOM_VCPU_CMD, 0)); | ||
2940 | radeon_ring_write(ring, 0); | ||
2941 | |||
2942 | radeon_ring_write(ring, PACKET0(UVD_GPCOM_VCPU_DATA0, 0)); | ||
2943 | radeon_ring_write(ring, 0); | ||
2944 | radeon_ring_write(ring, PACKET0(UVD_GPCOM_VCPU_DATA1, 0)); | ||
2945 | radeon_ring_write(ring, 0); | ||
2946 | radeon_ring_write(ring, PACKET0(UVD_GPCOM_VCPU_CMD, 0)); | ||
2947 | radeon_ring_write(ring, 2); | ||
2948 | return; | ||
2949 | } | ||
2950 | |||
2714 | void r600_semaphore_ring_emit(struct radeon_device *rdev, | 2951 | void r600_semaphore_ring_emit(struct radeon_device *rdev, |
2715 | struct radeon_ring *ring, | 2952 | struct radeon_ring *ring, |
2716 | struct radeon_semaphore *semaphore, | 2953 | struct radeon_semaphore *semaphore, |
@@ -2780,6 +3017,23 @@ void r600_dma_semaphore_ring_emit(struct radeon_device *rdev, | |||
2780 | radeon_ring_write(ring, upper_32_bits(addr) & 0xff); | 3017 | radeon_ring_write(ring, upper_32_bits(addr) & 0xff); |
2781 | } | 3018 | } |
2782 | 3019 | ||
3020 | void r600_uvd_semaphore_emit(struct radeon_device *rdev, | ||
3021 | struct radeon_ring *ring, | ||
3022 | struct radeon_semaphore *semaphore, | ||
3023 | bool emit_wait) | ||
3024 | { | ||
3025 | uint64_t addr = semaphore->gpu_addr; | ||
3026 | |||
3027 | radeon_ring_write(ring, PACKET0(UVD_SEMA_ADDR_LOW, 0)); | ||
3028 | radeon_ring_write(ring, (addr >> 3) & 0x000FFFFF); | ||
3029 | |||
3030 | radeon_ring_write(ring, PACKET0(UVD_SEMA_ADDR_HIGH, 0)); | ||
3031 | radeon_ring_write(ring, (addr >> 23) & 0x000FFFFF); | ||
3032 | |||
3033 | radeon_ring_write(ring, PACKET0(UVD_SEMA_CMD, 0)); | ||
3034 | radeon_ring_write(ring, emit_wait ? 1 : 0); | ||
3035 | } | ||
3036 | |||
2783 | int r600_copy_blit(struct radeon_device *rdev, | 3037 | int r600_copy_blit(struct radeon_device *rdev, |
2784 | uint64_t src_offset, | 3038 | uint64_t src_offset, |
2785 | uint64_t dst_offset, | 3039 | uint64_t dst_offset, |
@@ -3183,6 +3437,16 @@ void r600_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib) | |||
3183 | radeon_ring_write(ring, ib->length_dw); | 3437 | radeon_ring_write(ring, ib->length_dw); |
3184 | } | 3438 | } |
3185 | 3439 | ||
3440 | void r600_uvd_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib) | ||
3441 | { | ||
3442 | struct radeon_ring *ring = &rdev->ring[ib->ring]; | ||
3443 | |||
3444 | radeon_ring_write(ring, PACKET0(UVD_RBC_IB_BASE, 0)); | ||
3445 | radeon_ring_write(ring, ib->gpu_addr); | ||
3446 | radeon_ring_write(ring, PACKET0(UVD_RBC_IB_SIZE, 0)); | ||
3447 | radeon_ring_write(ring, ib->length_dw); | ||
3448 | } | ||
3449 | |||
3186 | int r600_ib_test(struct radeon_device *rdev, struct radeon_ring *ring) | 3450 | int r600_ib_test(struct radeon_device *rdev, struct radeon_ring *ring) |
3187 | { | 3451 | { |
3188 | struct radeon_ib ib; | 3452 | struct radeon_ib ib; |
@@ -3300,6 +3564,33 @@ int r600_dma_ib_test(struct radeon_device *rdev, struct radeon_ring *ring) | |||
3300 | return r; | 3564 | return r; |
3301 | } | 3565 | } |
3302 | 3566 | ||
3567 | int r600_uvd_ib_test(struct radeon_device *rdev, struct radeon_ring *ring) | ||
3568 | { | ||
3569 | struct radeon_fence *fence; | ||
3570 | int r; | ||
3571 | |||
3572 | r = radeon_uvd_get_create_msg(rdev, ring->idx, 1, NULL); | ||
3573 | if (r) { | ||
3574 | DRM_ERROR("radeon: failed to get create msg (%d).\n", r); | ||
3575 | return r; | ||
3576 | } | ||
3577 | |||
3578 | r = radeon_uvd_get_destroy_msg(rdev, ring->idx, 1, &fence); | ||
3579 | if (r) { | ||
3580 | DRM_ERROR("radeon: failed to get destroy ib (%d).\n", r); | ||
3581 | return r; | ||
3582 | } | ||
3583 | |||
3584 | r = radeon_fence_wait(fence, false); | ||
3585 | if (r) { | ||
3586 | DRM_ERROR("radeon: fence wait failed (%d).\n", r); | ||
3587 | return r; | ||
3588 | } | ||
3589 | DRM_INFO("ib test on ring %d succeeded\n", ring->idx); | ||
3590 | radeon_fence_unref(&fence); | ||
3591 | return r; | ||
3592 | } | ||
3593 | |||
3303 | /** | 3594 | /** |
3304 | * r600_dma_ring_ib_execute - Schedule an IB on the DMA engine | 3595 | * r600_dma_ring_ib_execute - Schedule an IB on the DMA engine |
3305 | * | 3596 | * |
diff --git a/drivers/gpu/drm/radeon/r600d.h b/drivers/gpu/drm/radeon/r600d.h index a42ba11a3bed..441bdb809a0b 100644 --- a/drivers/gpu/drm/radeon/r600d.h +++ b/drivers/gpu/drm/radeon/r600d.h | |||
@@ -691,6 +691,7 @@ | |||
691 | #define SRBM_SOFT_RESET 0xe60 | 691 | #define SRBM_SOFT_RESET 0xe60 |
692 | # define SOFT_RESET_DMA (1 << 12) | 692 | # define SOFT_RESET_DMA (1 << 12) |
693 | # define SOFT_RESET_RLC (1 << 13) | 693 | # define SOFT_RESET_RLC (1 << 13) |
694 | # define SOFT_RESET_UVD (1 << 18) | ||
694 | # define RV770_SOFT_RESET_DMA (1 << 20) | 695 | # define RV770_SOFT_RESET_DMA (1 << 20) |
695 | 696 | ||
696 | #define CP_INT_CNTL 0xc124 | 697 | #define CP_INT_CNTL 0xc124 |
@@ -1143,6 +1144,66 @@ | |||
1143 | # define AFMT_AZ_AUDIO_ENABLE_CHG_ACK (1 << 30) | 1144 | # define AFMT_AZ_AUDIO_ENABLE_CHG_ACK (1 << 30) |
1144 | 1145 | ||
1145 | /* | 1146 | /* |
1147 | * UVD | ||
1148 | */ | ||
1149 | #define UVD_SEMA_ADDR_LOW 0xef00 | ||
1150 | #define UVD_SEMA_ADDR_HIGH 0xef04 | ||
1151 | #define UVD_SEMA_CMD 0xef08 | ||
1152 | |||
1153 | #define UVD_GPCOM_VCPU_CMD 0xef0c | ||
1154 | #define UVD_GPCOM_VCPU_DATA0 0xef10 | ||
1155 | #define UVD_GPCOM_VCPU_DATA1 0xef14 | ||
1156 | #define UVD_ENGINE_CNTL 0xef18 | ||
1157 | |||
1158 | #define UVD_SEMA_CNTL 0xf400 | ||
1159 | #define UVD_RB_ARB_CTRL 0xf480 | ||
1160 | |||
1161 | #define UVD_LMI_EXT40_ADDR 0xf498 | ||
1162 | #define UVD_CGC_GATE 0xf4a8 | ||
1163 | #define UVD_LMI_CTRL2 0xf4f4 | ||
1164 | #define UVD_MASTINT_EN 0xf500 | ||
1165 | #define UVD_LMI_ADDR_EXT 0xf594 | ||
1166 | #define UVD_LMI_CTRL 0xf598 | ||
1167 | #define UVD_LMI_SWAP_CNTL 0xf5b4 | ||
1168 | #define UVD_MP_SWAP_CNTL 0xf5bC | ||
1169 | #define UVD_MPC_CNTL 0xf5dC | ||
1170 | #define UVD_MPC_SET_MUXA0 0xf5e4 | ||
1171 | #define UVD_MPC_SET_MUXA1 0xf5e8 | ||
1172 | #define UVD_MPC_SET_MUXB0 0xf5eC | ||
1173 | #define UVD_MPC_SET_MUXB1 0xf5f0 | ||
1174 | #define UVD_MPC_SET_MUX 0xf5f4 | ||
1175 | #define UVD_MPC_SET_ALU 0xf5f8 | ||
1176 | |||
1177 | #define UVD_VCPU_CNTL 0xf660 | ||
1178 | #define UVD_SOFT_RESET 0xf680 | ||
1179 | #define RBC_SOFT_RESET (1<<0) | ||
1180 | #define LBSI_SOFT_RESET (1<<1) | ||
1181 | #define LMI_SOFT_RESET (1<<2) | ||
1182 | #define VCPU_SOFT_RESET (1<<3) | ||
1183 | #define CSM_SOFT_RESET (1<<5) | ||
1184 | #define CXW_SOFT_RESET (1<<6) | ||
1185 | #define TAP_SOFT_RESET (1<<7) | ||
1186 | #define LMI_UMC_SOFT_RESET (1<<13) | ||
1187 | #define UVD_RBC_IB_BASE 0xf684 | ||
1188 | #define UVD_RBC_IB_SIZE 0xf688 | ||
1189 | #define UVD_RBC_RB_BASE 0xf68c | ||
1190 | #define UVD_RBC_RB_RPTR 0xf690 | ||
1191 | #define UVD_RBC_RB_WPTR 0xf694 | ||
1192 | #define UVD_RBC_RB_WPTR_CNTL 0xf698 | ||
1193 | |||
1194 | #define UVD_STATUS 0xf6bc | ||
1195 | |||
1196 | #define UVD_SEMA_TIMEOUT_STATUS 0xf6c0 | ||
1197 | #define UVD_SEMA_WAIT_INCOMPLETE_TIMEOUT_CNTL 0xf6c4 | ||
1198 | #define UVD_SEMA_WAIT_FAULT_TIMEOUT_CNTL 0xf6c8 | ||
1199 | #define UVD_SEMA_SIGNAL_INCOMPLETE_TIMEOUT_CNTL 0xf6cc | ||
1200 | |||
1201 | #define UVD_RBC_RB_CNTL 0xf6a4 | ||
1202 | #define UVD_RBC_RB_RPTR_ADDR 0xf6a8 | ||
1203 | |||
1204 | #define UVD_CONTEXT_ID 0xf6f4 | ||
1205 | |||
1206 | /* | ||
1146 | * PM4 | 1207 | * PM4 |
1147 | */ | 1208 | */ |
1148 | #define PACKET0(reg, n) ((RADEON_PACKET_TYPE0 << 30) | \ | 1209 | #define PACKET0(reg, n) ((RADEON_PACKET_TYPE0 << 30) | \ |
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 3db6b02c4263..66e68c1a578f 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h | |||
@@ -110,24 +110,27 @@ extern int radeon_fastfb; | |||
110 | #define RADEON_BIOS_NUM_SCRATCH 8 | 110 | #define RADEON_BIOS_NUM_SCRATCH 8 |
111 | 111 | ||
112 | /* max number of rings */ | 112 | /* max number of rings */ |
113 | #define RADEON_NUM_RINGS 5 | 113 | #define RADEON_NUM_RINGS 6 |
114 | 114 | ||
115 | /* fence seq are set to this number when signaled */ | 115 | /* fence seq are set to this number when signaled */ |
116 | #define RADEON_FENCE_SIGNALED_SEQ 0LL | 116 | #define RADEON_FENCE_SIGNALED_SEQ 0LL |
117 | 117 | ||
118 | /* internal ring indices */ | 118 | /* internal ring indices */ |
119 | /* r1xx+ has gfx CP ring */ | 119 | /* r1xx+ has gfx CP ring */ |
120 | #define RADEON_RING_TYPE_GFX_INDEX 0 | 120 | #define RADEON_RING_TYPE_GFX_INDEX 0 |
121 | 121 | ||
122 | /* cayman has 2 compute CP rings */ | 122 | /* cayman has 2 compute CP rings */ |
123 | #define CAYMAN_RING_TYPE_CP1_INDEX 1 | 123 | #define CAYMAN_RING_TYPE_CP1_INDEX 1 |
124 | #define CAYMAN_RING_TYPE_CP2_INDEX 2 | 124 | #define CAYMAN_RING_TYPE_CP2_INDEX 2 |
125 | 125 | ||
126 | /* R600+ has an async dma ring */ | 126 | /* R600+ has an async dma ring */ |
127 | #define R600_RING_TYPE_DMA_INDEX 3 | 127 | #define R600_RING_TYPE_DMA_INDEX 3 |
128 | /* cayman add a second async dma ring */ | 128 | /* cayman add a second async dma ring */ |
129 | #define CAYMAN_RING_TYPE_DMA1_INDEX 4 | 129 | #define CAYMAN_RING_TYPE_DMA1_INDEX 4 |
130 | 130 | ||
131 | /* R600+ */ | ||
132 | #define R600_RING_TYPE_UVD_INDEX 5 | ||
133 | |||
131 | /* hardcode those limit for now */ | 134 | /* hardcode those limit for now */ |
132 | #define RADEON_VA_IB_OFFSET (1 << 20) | 135 | #define RADEON_VA_IB_OFFSET (1 << 20) |
133 | #define RADEON_VA_RESERVED_SIZE (8 << 20) | 136 | #define RADEON_VA_RESERVED_SIZE (8 << 20) |
@@ -921,6 +924,7 @@ struct radeon_wb { | |||
921 | #define R600_WB_DMA_RPTR_OFFSET 1792 | 924 | #define R600_WB_DMA_RPTR_OFFSET 1792 |
922 | #define R600_WB_IH_WPTR_OFFSET 2048 | 925 | #define R600_WB_IH_WPTR_OFFSET 2048 |
923 | #define CAYMAN_WB_DMA1_RPTR_OFFSET 2304 | 926 | #define CAYMAN_WB_DMA1_RPTR_OFFSET 2304 |
927 | #define R600_WB_UVD_RPTR_OFFSET 2560 | ||
924 | #define R600_WB_EVENT_OFFSET 3072 | 928 | #define R600_WB_EVENT_OFFSET 3072 |
925 | 929 | ||
926 | /** | 930 | /** |
@@ -1121,6 +1125,33 @@ struct radeon_pm { | |||
1121 | int radeon_pm_get_type_index(struct radeon_device *rdev, | 1125 | int radeon_pm_get_type_index(struct radeon_device *rdev, |
1122 | enum radeon_pm_state_type ps_type, | 1126 | enum radeon_pm_state_type ps_type, |
1123 | int instance); | 1127 | int instance); |
1128 | /* | ||
1129 | * UVD | ||
1130 | */ | ||
1131 | #define RADEON_MAX_UVD_HANDLES 10 | ||
1132 | #define RADEON_UVD_STACK_SIZE (1024*1024) | ||
1133 | #define RADEON_UVD_HEAP_SIZE (1024*1024) | ||
1134 | |||
1135 | struct radeon_uvd { | ||
1136 | struct radeon_bo *vcpu_bo; | ||
1137 | void *cpu_addr; | ||
1138 | uint64_t gpu_addr; | ||
1139 | atomic_t handles[RADEON_MAX_UVD_HANDLES]; | ||
1140 | struct drm_file *filp[RADEON_MAX_UVD_HANDLES]; | ||
1141 | }; | ||
1142 | |||
1143 | int radeon_uvd_init(struct radeon_device *rdev); | ||
1144 | void radeon_uvd_fini(struct radeon_device *rdev); | ||
1145 | int radeon_uvd_suspend(struct radeon_device *rdev); | ||
1146 | int radeon_uvd_resume(struct radeon_device *rdev); | ||
1147 | int radeon_uvd_get_create_msg(struct radeon_device *rdev, int ring, | ||
1148 | uint32_t handle, struct radeon_fence **fence); | ||
1149 | int radeon_uvd_get_destroy_msg(struct radeon_device *rdev, int ring, | ||
1150 | uint32_t handle, struct radeon_fence **fence); | ||
1151 | void radeon_uvd_force_into_uvd_segment(struct radeon_bo *rbo); | ||
1152 | void radeon_uvd_free_handles(struct radeon_device *rdev, | ||
1153 | struct drm_file *filp); | ||
1154 | int radeon_uvd_cs_parse(struct radeon_cs_parser *parser); | ||
1124 | 1155 | ||
1125 | struct r600_audio { | 1156 | struct r600_audio { |
1126 | int channels; | 1157 | int channels; |
@@ -1611,6 +1642,7 @@ struct radeon_device { | |||
1611 | struct radeon_asic *asic; | 1642 | struct radeon_asic *asic; |
1612 | struct radeon_gem gem; | 1643 | struct radeon_gem gem; |
1613 | struct radeon_pm pm; | 1644 | struct radeon_pm pm; |
1645 | struct radeon_uvd uvd; | ||
1614 | uint32_t bios_scratch[RADEON_BIOS_NUM_SCRATCH]; | 1646 | uint32_t bios_scratch[RADEON_BIOS_NUM_SCRATCH]; |
1615 | struct radeon_wb wb; | 1647 | struct radeon_wb wb; |
1616 | struct radeon_dummy_page dummy_page; | 1648 | struct radeon_dummy_page dummy_page; |
@@ -1625,6 +1657,7 @@ struct radeon_device { | |||
1625 | const struct firmware *rlc_fw; /* r6/700 RLC firmware */ | 1657 | const struct firmware *rlc_fw; /* r6/700 RLC firmware */ |
1626 | const struct firmware *mc_fw; /* NI MC firmware */ | 1658 | const struct firmware *mc_fw; /* NI MC firmware */ |
1627 | const struct firmware *ce_fw; /* SI CE firmware */ | 1659 | const struct firmware *ce_fw; /* SI CE firmware */ |
1660 | const struct firmware *uvd_fw; /* UVD firmware */ | ||
1628 | struct r600_blit r600_blit; | 1661 | struct r600_blit r600_blit; |
1629 | struct r600_vram_scratch vram_scratch; | 1662 | struct r600_vram_scratch vram_scratch; |
1630 | int msi_enabled; /* msi enabled */ | 1663 | int msi_enabled; /* msi enabled */ |
diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c index aba0a893ea98..a7a7b2bc4204 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.c +++ b/drivers/gpu/drm/radeon/radeon_asic.c | |||
@@ -1130,6 +1130,15 @@ static struct radeon_asic rv770_asic = { | |||
1130 | .ring_test = &r600_dma_ring_test, | 1130 | .ring_test = &r600_dma_ring_test, |
1131 | .ib_test = &r600_dma_ib_test, | 1131 | .ib_test = &r600_dma_ib_test, |
1132 | .is_lockup = &r600_dma_is_lockup, | 1132 | .is_lockup = &r600_dma_is_lockup, |
1133 | }, | ||
1134 | [R600_RING_TYPE_UVD_INDEX] = { | ||
1135 | .ib_execute = &r600_uvd_ib_execute, | ||
1136 | .emit_fence = &r600_uvd_fence_emit, | ||
1137 | .emit_semaphore = &r600_uvd_semaphore_emit, | ||
1138 | .cs_parse = &radeon_uvd_cs_parse, | ||
1139 | .ring_test = &r600_uvd_ring_test, | ||
1140 | .ib_test = &r600_uvd_ib_test, | ||
1141 | .is_lockup = &radeon_ring_test_lockup, | ||
1133 | } | 1142 | } |
1134 | }, | 1143 | }, |
1135 | .irq = { | 1144 | .irq = { |
@@ -1216,6 +1225,15 @@ static struct radeon_asic evergreen_asic = { | |||
1216 | .ring_test = &r600_dma_ring_test, | 1225 | .ring_test = &r600_dma_ring_test, |
1217 | .ib_test = &r600_dma_ib_test, | 1226 | .ib_test = &r600_dma_ib_test, |
1218 | .is_lockup = &evergreen_dma_is_lockup, | 1227 | .is_lockup = &evergreen_dma_is_lockup, |
1228 | }, | ||
1229 | [R600_RING_TYPE_UVD_INDEX] = { | ||
1230 | .ib_execute = &r600_uvd_ib_execute, | ||
1231 | .emit_fence = &r600_uvd_fence_emit, | ||
1232 | .emit_semaphore = &r600_uvd_semaphore_emit, | ||
1233 | .cs_parse = &radeon_uvd_cs_parse, | ||
1234 | .ring_test = &r600_uvd_ring_test, | ||
1235 | .ib_test = &r600_uvd_ib_test, | ||
1236 | .is_lockup = &radeon_ring_test_lockup, | ||
1219 | } | 1237 | } |
1220 | }, | 1238 | }, |
1221 | .irq = { | 1239 | .irq = { |
@@ -1302,6 +1320,15 @@ static struct radeon_asic sumo_asic = { | |||
1302 | .ring_test = &r600_dma_ring_test, | 1320 | .ring_test = &r600_dma_ring_test, |
1303 | .ib_test = &r600_dma_ib_test, | 1321 | .ib_test = &r600_dma_ib_test, |
1304 | .is_lockup = &evergreen_dma_is_lockup, | 1322 | .is_lockup = &evergreen_dma_is_lockup, |
1323 | }, | ||
1324 | [R600_RING_TYPE_UVD_INDEX] = { | ||
1325 | .ib_execute = &r600_uvd_ib_execute, | ||
1326 | .emit_fence = &r600_uvd_fence_emit, | ||
1327 | .emit_semaphore = &r600_uvd_semaphore_emit, | ||
1328 | .cs_parse = &radeon_uvd_cs_parse, | ||
1329 | .ring_test = &r600_uvd_ring_test, | ||
1330 | .ib_test = &r600_uvd_ib_test, | ||
1331 | .is_lockup = &radeon_ring_test_lockup, | ||
1305 | } | 1332 | } |
1306 | }, | 1333 | }, |
1307 | .irq = { | 1334 | .irq = { |
@@ -1388,6 +1415,15 @@ static struct radeon_asic btc_asic = { | |||
1388 | .ring_test = &r600_dma_ring_test, | 1415 | .ring_test = &r600_dma_ring_test, |
1389 | .ib_test = &r600_dma_ib_test, | 1416 | .ib_test = &r600_dma_ib_test, |
1390 | .is_lockup = &evergreen_dma_is_lockup, | 1417 | .is_lockup = &evergreen_dma_is_lockup, |
1418 | }, | ||
1419 | [R600_RING_TYPE_UVD_INDEX] = { | ||
1420 | .ib_execute = &r600_uvd_ib_execute, | ||
1421 | .emit_fence = &r600_uvd_fence_emit, | ||
1422 | .emit_semaphore = &r600_uvd_semaphore_emit, | ||
1423 | .cs_parse = &radeon_uvd_cs_parse, | ||
1424 | .ring_test = &r600_uvd_ring_test, | ||
1425 | .ib_test = &r600_uvd_ib_test, | ||
1426 | .is_lockup = &radeon_ring_test_lockup, | ||
1391 | } | 1427 | } |
1392 | }, | 1428 | }, |
1393 | .irq = { | 1429 | .irq = { |
@@ -1517,6 +1553,15 @@ static struct radeon_asic cayman_asic = { | |||
1517 | .ib_test = &r600_dma_ib_test, | 1553 | .ib_test = &r600_dma_ib_test, |
1518 | .is_lockup = &cayman_dma_is_lockup, | 1554 | .is_lockup = &cayman_dma_is_lockup, |
1519 | .vm_flush = &cayman_dma_vm_flush, | 1555 | .vm_flush = &cayman_dma_vm_flush, |
1556 | }, | ||
1557 | [R600_RING_TYPE_UVD_INDEX] = { | ||
1558 | .ib_execute = &r600_uvd_ib_execute, | ||
1559 | .emit_fence = &r600_uvd_fence_emit, | ||
1560 | .emit_semaphore = &cayman_uvd_semaphore_emit, | ||
1561 | .cs_parse = &radeon_uvd_cs_parse, | ||
1562 | .ring_test = &r600_uvd_ring_test, | ||
1563 | .ib_test = &r600_uvd_ib_test, | ||
1564 | .is_lockup = &radeon_ring_test_lockup, | ||
1520 | } | 1565 | } |
1521 | }, | 1566 | }, |
1522 | .irq = { | 1567 | .irq = { |
@@ -1646,6 +1691,15 @@ static struct radeon_asic trinity_asic = { | |||
1646 | .ib_test = &r600_dma_ib_test, | 1691 | .ib_test = &r600_dma_ib_test, |
1647 | .is_lockup = &cayman_dma_is_lockup, | 1692 | .is_lockup = &cayman_dma_is_lockup, |
1648 | .vm_flush = &cayman_dma_vm_flush, | 1693 | .vm_flush = &cayman_dma_vm_flush, |
1694 | }, | ||
1695 | [R600_RING_TYPE_UVD_INDEX] = { | ||
1696 | .ib_execute = &r600_uvd_ib_execute, | ||
1697 | .emit_fence = &r600_uvd_fence_emit, | ||
1698 | .emit_semaphore = &cayman_uvd_semaphore_emit, | ||
1699 | .cs_parse = &radeon_uvd_cs_parse, | ||
1700 | .ring_test = &r600_uvd_ring_test, | ||
1701 | .ib_test = &r600_uvd_ib_test, | ||
1702 | .is_lockup = &radeon_ring_test_lockup, | ||
1649 | } | 1703 | } |
1650 | }, | 1704 | }, |
1651 | .irq = { | 1705 | .irq = { |
@@ -1775,6 +1829,15 @@ static struct radeon_asic si_asic = { | |||
1775 | .ib_test = &r600_dma_ib_test, | 1829 | .ib_test = &r600_dma_ib_test, |
1776 | .is_lockup = &si_dma_is_lockup, | 1830 | .is_lockup = &si_dma_is_lockup, |
1777 | .vm_flush = &si_dma_vm_flush, | 1831 | .vm_flush = &si_dma_vm_flush, |
1832 | }, | ||
1833 | [R600_RING_TYPE_UVD_INDEX] = { | ||
1834 | .ib_execute = &r600_uvd_ib_execute, | ||
1835 | .emit_fence = &r600_uvd_fence_emit, | ||
1836 | .emit_semaphore = &cayman_uvd_semaphore_emit, | ||
1837 | .cs_parse = &radeon_uvd_cs_parse, | ||
1838 | .ring_test = &r600_uvd_ring_test, | ||
1839 | .ib_test = &r600_uvd_ib_test, | ||
1840 | .is_lockup = &radeon_ring_test_lockup, | ||
1778 | } | 1841 | } |
1779 | }, | 1842 | }, |
1780 | .irq = { | 1843 | .irq = { |
diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h index 3535f73ad3e2..515db96e3e2c 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.h +++ b/drivers/gpu/drm/radeon/radeon_asic.h | |||
@@ -330,6 +330,7 @@ int r600_dma_ib_test(struct radeon_device *rdev, struct radeon_ring *ring); | |||
330 | void r600_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib); | 330 | void r600_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib); |
331 | int r600_ring_test(struct radeon_device *rdev, struct radeon_ring *cp); | 331 | int r600_ring_test(struct radeon_device *rdev, struct radeon_ring *cp); |
332 | int r600_dma_ring_test(struct radeon_device *rdev, struct radeon_ring *cp); | 332 | int r600_dma_ring_test(struct radeon_device *rdev, struct radeon_ring *cp); |
333 | int r600_uvd_ring_test(struct radeon_device *rdev, struct radeon_ring *ring); | ||
333 | int r600_copy_blit(struct radeon_device *rdev, | 334 | int r600_copy_blit(struct radeon_device *rdev, |
334 | uint64_t src_offset, uint64_t dst_offset, | 335 | uint64_t src_offset, uint64_t dst_offset, |
335 | unsigned num_gpu_pages, struct radeon_fence **fence); | 336 | unsigned num_gpu_pages, struct radeon_fence **fence); |
@@ -392,6 +393,19 @@ int r600_mc_wait_for_idle(struct radeon_device *rdev); | |||
392 | u32 r600_get_xclk(struct radeon_device *rdev); | 393 | u32 r600_get_xclk(struct radeon_device *rdev); |
393 | uint64_t r600_get_gpu_clock_counter(struct radeon_device *rdev); | 394 | uint64_t r600_get_gpu_clock_counter(struct radeon_device *rdev); |
394 | 395 | ||
396 | /* uvd */ | ||
397 | int r600_uvd_init(struct radeon_device *rdev); | ||
398 | int r600_uvd_rbc_start(struct radeon_device *rdev); | ||
399 | void r600_uvd_rbc_stop(struct radeon_device *rdev); | ||
400 | int r600_uvd_ib_test(struct radeon_device *rdev, struct radeon_ring *ring); | ||
401 | void r600_uvd_fence_emit(struct radeon_device *rdev, | ||
402 | struct radeon_fence *fence); | ||
403 | void r600_uvd_semaphore_emit(struct radeon_device *rdev, | ||
404 | struct radeon_ring *ring, | ||
405 | struct radeon_semaphore *semaphore, | ||
406 | bool emit_wait); | ||
407 | void r600_uvd_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib); | ||
408 | |||
395 | /* | 409 | /* |
396 | * rv770,rv730,rv710,rv740 | 410 | * rv770,rv730,rv710,rv740 |
397 | */ | 411 | */ |
@@ -409,6 +423,7 @@ int rv770_copy_dma(struct radeon_device *rdev, | |||
409 | unsigned num_gpu_pages, | 423 | unsigned num_gpu_pages, |
410 | struct radeon_fence **fence); | 424 | struct radeon_fence **fence); |
411 | u32 rv770_get_xclk(struct radeon_device *rdev); | 425 | u32 rv770_get_xclk(struct radeon_device *rdev); |
426 | int rv770_uvd_resume(struct radeon_device *rdev); | ||
412 | 427 | ||
413 | /* | 428 | /* |
414 | * evergreen | 429 | * evergreen |
@@ -465,6 +480,10 @@ int evergreen_copy_dma(struct radeon_device *rdev, | |||
465 | */ | 480 | */ |
466 | void cayman_fence_ring_emit(struct radeon_device *rdev, | 481 | void cayman_fence_ring_emit(struct radeon_device *rdev, |
467 | struct radeon_fence *fence); | 482 | struct radeon_fence *fence); |
483 | void cayman_uvd_semaphore_emit(struct radeon_device *rdev, | ||
484 | struct radeon_ring *ring, | ||
485 | struct radeon_semaphore *semaphore, | ||
486 | bool emit_wait); | ||
468 | void cayman_pcie_gart_tlb_flush(struct radeon_device *rdev); | 487 | void cayman_pcie_gart_tlb_flush(struct radeon_device *rdev); |
469 | int cayman_init(struct radeon_device *rdev); | 488 | int cayman_init(struct radeon_device *rdev); |
470 | void cayman_fini(struct radeon_device *rdev); | 489 | void cayman_fini(struct radeon_device *rdev); |
diff --git a/drivers/gpu/drm/radeon/radeon_cs.c b/drivers/gpu/drm/radeon/radeon_cs.c index c9ee4c02522a..c7407074c09b 100644 --- a/drivers/gpu/drm/radeon/radeon_cs.c +++ b/drivers/gpu/drm/radeon/radeon_cs.c | |||
@@ -53,7 +53,6 @@ static int radeon_cs_parser_relocs(struct radeon_cs_parser *p) | |||
53 | } | 53 | } |
54 | for (i = 0; i < p->nrelocs; i++) { | 54 | for (i = 0; i < p->nrelocs; i++) { |
55 | struct drm_radeon_cs_reloc *r; | 55 | struct drm_radeon_cs_reloc *r; |
56 | uint32_t domain; | ||
57 | 56 | ||
58 | duplicate = false; | 57 | duplicate = false; |
59 | r = (struct drm_radeon_cs_reloc *)&chunk->kdata[i*4]; | 58 | r = (struct drm_radeon_cs_reloc *)&chunk->kdata[i*4]; |
@@ -81,11 +80,25 @@ static int radeon_cs_parser_relocs(struct radeon_cs_parser *p) | |||
81 | p->relocs[i].lobj.bo = p->relocs[i].robj; | 80 | p->relocs[i].lobj.bo = p->relocs[i].robj; |
82 | p->relocs[i].lobj.written = !!r->write_domain; | 81 | p->relocs[i].lobj.written = !!r->write_domain; |
83 | 82 | ||
84 | domain = r->write_domain ? r->write_domain : r->read_domains; | 83 | /* the first reloc of an UVD job is the |
85 | p->relocs[i].lobj.domain = domain; | 84 | msg and that must be in VRAM */ |
86 | if (domain == RADEON_GEM_DOMAIN_VRAM) | 85 | if (p->ring == R600_RING_TYPE_UVD_INDEX && i == 0) { |
87 | domain |= RADEON_GEM_DOMAIN_GTT; | 86 | /* TODO: is this still needed for NI+ ? */ |
88 | p->relocs[i].lobj.alt_domain = domain; | 87 | p->relocs[i].lobj.domain = |
88 | RADEON_GEM_DOMAIN_VRAM; | ||
89 | |||
90 | p->relocs[i].lobj.alt_domain = | ||
91 | RADEON_GEM_DOMAIN_VRAM; | ||
92 | |||
93 | } else { | ||
94 | uint32_t domain = r->write_domain ? | ||
95 | r->write_domain : r->read_domains; | ||
96 | |||
97 | p->relocs[i].lobj.domain = domain; | ||
98 | if (domain == RADEON_GEM_DOMAIN_VRAM) | ||
99 | domain |= RADEON_GEM_DOMAIN_GTT; | ||
100 | p->relocs[i].lobj.alt_domain = domain; | ||
101 | } | ||
89 | 102 | ||
90 | p->relocs[i].lobj.tv.bo = &p->relocs[i].robj->tbo; | 103 | p->relocs[i].lobj.tv.bo = &p->relocs[i].robj->tbo; |
91 | p->relocs[i].handle = r->handle; | 104 | p->relocs[i].handle = r->handle; |
@@ -93,7 +106,7 @@ static int radeon_cs_parser_relocs(struct radeon_cs_parser *p) | |||
93 | radeon_bo_list_add_object(&p->relocs[i].lobj, | 106 | radeon_bo_list_add_object(&p->relocs[i].lobj, |
94 | &p->validated); | 107 | &p->validated); |
95 | } | 108 | } |
96 | return radeon_bo_list_validate(&p->validated); | 109 | return radeon_bo_list_validate(&p->validated, p->ring); |
97 | } | 110 | } |
98 | 111 | ||
99 | static int radeon_cs_get_ring(struct radeon_cs_parser *p, u32 ring, s32 priority) | 112 | static int radeon_cs_get_ring(struct radeon_cs_parser *p, u32 ring, s32 priority) |
@@ -128,6 +141,9 @@ static int radeon_cs_get_ring(struct radeon_cs_parser *p, u32 ring, s32 priority | |||
128 | return -EINVAL; | 141 | return -EINVAL; |
129 | } | 142 | } |
130 | break; | 143 | break; |
144 | case RADEON_CS_RING_UVD: | ||
145 | p->ring = R600_RING_TYPE_UVD_INDEX; | ||
146 | break; | ||
131 | } | 147 | } |
132 | return 0; | 148 | return 0; |
133 | } | 149 | } |
diff --git a/drivers/gpu/drm/radeon/radeon_fence.c b/drivers/gpu/drm/radeon/radeon_fence.c index 34356252567a..82fe1835ff8c 100644 --- a/drivers/gpu/drm/radeon/radeon_fence.c +++ b/drivers/gpu/drm/radeon/radeon_fence.c | |||
@@ -31,9 +31,9 @@ | |||
31 | #include <linux/seq_file.h> | 31 | #include <linux/seq_file.h> |
32 | #include <linux/atomic.h> | 32 | #include <linux/atomic.h> |
33 | #include <linux/wait.h> | 33 | #include <linux/wait.h> |
34 | #include <linux/list.h> | ||
35 | #include <linux/kref.h> | 34 | #include <linux/kref.h> |
36 | #include <linux/slab.h> | 35 | #include <linux/slab.h> |
36 | #include <linux/firmware.h> | ||
37 | #include <drm/drmP.h> | 37 | #include <drm/drmP.h> |
38 | #include "radeon_reg.h" | 38 | #include "radeon_reg.h" |
39 | #include "radeon.h" | 39 | #include "radeon.h" |
@@ -767,8 +767,21 @@ int radeon_fence_driver_start_ring(struct radeon_device *rdev, int ring) | |||
767 | 767 | ||
768 | radeon_scratch_free(rdev, rdev->fence_drv[ring].scratch_reg); | 768 | radeon_scratch_free(rdev, rdev->fence_drv[ring].scratch_reg); |
769 | if (rdev->wb.use_event || !radeon_ring_supports_scratch_reg(rdev, &rdev->ring[ring])) { | 769 | if (rdev->wb.use_event || !radeon_ring_supports_scratch_reg(rdev, &rdev->ring[ring])) { |
770 | rdev->fence_drv[ring].scratch_reg = 0; | 770 | if (ring != R600_RING_TYPE_UVD_INDEX) { |
771 | index = R600_WB_EVENT_OFFSET + ring * 4; | 771 | rdev->fence_drv[ring].scratch_reg = 0; |
772 | index = R600_WB_EVENT_OFFSET + ring * 4; | ||
773 | rdev->fence_drv[ring].cpu_addr = &rdev->wb.wb[index/4]; | ||
774 | rdev->fence_drv[ring].gpu_addr = rdev->wb.gpu_addr + | ||
775 | index; | ||
776 | |||
777 | } else { | ||
778 | /* put fence directly behind firmware */ | ||
779 | rdev->fence_drv[ring].cpu_addr = rdev->uvd.cpu_addr + | ||
780 | rdev->uvd_fw->size; | ||
781 | rdev->fence_drv[ring].gpu_addr = rdev->uvd.gpu_addr + | ||
782 | rdev->uvd_fw->size; | ||
783 | } | ||
784 | |||
772 | } else { | 785 | } else { |
773 | r = radeon_scratch_get(rdev, &rdev->fence_drv[ring].scratch_reg); | 786 | r = radeon_scratch_get(rdev, &rdev->fence_drv[ring].scratch_reg); |
774 | if (r) { | 787 | if (r) { |
@@ -778,9 +791,9 @@ int radeon_fence_driver_start_ring(struct radeon_device *rdev, int ring) | |||
778 | index = RADEON_WB_SCRATCH_OFFSET + | 791 | index = RADEON_WB_SCRATCH_OFFSET + |
779 | rdev->fence_drv[ring].scratch_reg - | 792 | rdev->fence_drv[ring].scratch_reg - |
780 | rdev->scratch.reg_base; | 793 | rdev->scratch.reg_base; |
794 | rdev->fence_drv[ring].cpu_addr = &rdev->wb.wb[index/4]; | ||
795 | rdev->fence_drv[ring].gpu_addr = rdev->wb.gpu_addr + index; | ||
781 | } | 796 | } |
782 | rdev->fence_drv[ring].cpu_addr = &rdev->wb.wb[index/4]; | ||
783 | rdev->fence_drv[ring].gpu_addr = rdev->wb.gpu_addr + index; | ||
784 | radeon_fence_write(rdev, atomic64_read(&rdev->fence_drv[ring].last_seq), ring); | 797 | radeon_fence_write(rdev, atomic64_read(&rdev->fence_drv[ring].last_seq), ring); |
785 | rdev->fence_drv[ring].initialized = true; | 798 | rdev->fence_drv[ring].initialized = true; |
786 | dev_info(rdev->dev, "fence driver on ring %d use gpu addr 0x%016llx and cpu addr 0x%p\n", | 799 | dev_info(rdev->dev, "fence driver on ring %d use gpu addr 0x%016llx and cpu addr 0x%p\n", |
diff --git a/drivers/gpu/drm/radeon/radeon_kms.c b/drivers/gpu/drm/radeon/radeon_kms.c index f5464482dee8..8365c75b31b6 100644 --- a/drivers/gpu/drm/radeon/radeon_kms.c +++ b/drivers/gpu/drm/radeon/radeon_kms.c | |||
@@ -516,6 +516,7 @@ void radeon_driver_preclose_kms(struct drm_device *dev, | |||
516 | rdev->hyperz_filp = NULL; | 516 | rdev->hyperz_filp = NULL; |
517 | if (rdev->cmask_filp == file_priv) | 517 | if (rdev->cmask_filp == file_priv) |
518 | rdev->cmask_filp = NULL; | 518 | rdev->cmask_filp = NULL; |
519 | radeon_uvd_free_handles(rdev, file_priv); | ||
519 | } | 520 | } |
520 | 521 | ||
521 | /* | 522 | /* |
diff --git a/drivers/gpu/drm/radeon/radeon_object.c b/drivers/gpu/drm/radeon/radeon_object.c index 4466477f1e7b..1424ccde2377 100644 --- a/drivers/gpu/drm/radeon/radeon_object.c +++ b/drivers/gpu/drm/radeon/radeon_object.c | |||
@@ -348,7 +348,7 @@ void radeon_bo_list_add_object(struct radeon_bo_list *lobj, | |||
348 | } | 348 | } |
349 | } | 349 | } |
350 | 350 | ||
351 | int radeon_bo_list_validate(struct list_head *head) | 351 | int radeon_bo_list_validate(struct list_head *head, int ring) |
352 | { | 352 | { |
353 | struct radeon_bo_list *lobj; | 353 | struct radeon_bo_list *lobj; |
354 | struct radeon_bo *bo; | 354 | struct radeon_bo *bo; |
@@ -366,6 +366,8 @@ int radeon_bo_list_validate(struct list_head *head) | |||
366 | 366 | ||
367 | retry: | 367 | retry: |
368 | radeon_ttm_placement_from_domain(bo, domain); | 368 | radeon_ttm_placement_from_domain(bo, domain); |
369 | if (ring == R600_RING_TYPE_UVD_INDEX) | ||
370 | radeon_uvd_force_into_uvd_segment(bo); | ||
369 | r = ttm_bo_validate(&bo->tbo, &bo->placement, | 371 | r = ttm_bo_validate(&bo->tbo, &bo->placement, |
370 | true, false); | 372 | true, false); |
371 | if (unlikely(r)) { | 373 | if (unlikely(r)) { |
diff --git a/drivers/gpu/drm/radeon/radeon_object.h b/drivers/gpu/drm/radeon/radeon_object.h index 5fc86b03043b..e2cb80a96b51 100644 --- a/drivers/gpu/drm/radeon/radeon_object.h +++ b/drivers/gpu/drm/radeon/radeon_object.h | |||
@@ -128,7 +128,7 @@ extern int radeon_bo_init(struct radeon_device *rdev); | |||
128 | extern void radeon_bo_fini(struct radeon_device *rdev); | 128 | extern void radeon_bo_fini(struct radeon_device *rdev); |
129 | extern void radeon_bo_list_add_object(struct radeon_bo_list *lobj, | 129 | extern void radeon_bo_list_add_object(struct radeon_bo_list *lobj, |
130 | struct list_head *head); | 130 | struct list_head *head); |
131 | extern int radeon_bo_list_validate(struct list_head *head); | 131 | extern int radeon_bo_list_validate(struct list_head *head, int ring); |
132 | extern int radeon_bo_fbdev_mmap(struct radeon_bo *bo, | 132 | extern int radeon_bo_fbdev_mmap(struct radeon_bo *bo, |
133 | struct vm_area_struct *vma); | 133 | struct vm_area_struct *vma); |
134 | extern int radeon_bo_set_tiling_flags(struct radeon_bo *bo, | 134 | extern int radeon_bo_set_tiling_flags(struct radeon_bo *bo, |
diff --git a/drivers/gpu/drm/radeon/radeon_ring.c b/drivers/gpu/drm/radeon/radeon_ring.c index 8d58e268ff6d..31e47d898c46 100644 --- a/drivers/gpu/drm/radeon/radeon_ring.c +++ b/drivers/gpu/drm/radeon/radeon_ring.c | |||
@@ -368,7 +368,7 @@ void radeon_ring_free_size(struct radeon_device *rdev, struct radeon_ring *ring) | |||
368 | { | 368 | { |
369 | u32 rptr; | 369 | u32 rptr; |
370 | 370 | ||
371 | if (rdev->wb.enabled) | 371 | if (rdev->wb.enabled && ring != &rdev->ring[R600_RING_TYPE_UVD_INDEX]) |
372 | rptr = le32_to_cpu(rdev->wb.wb[ring->rptr_offs/4]); | 372 | rptr = le32_to_cpu(rdev->wb.wb[ring->rptr_offs/4]); |
373 | else | 373 | else |
374 | rptr = RREG32(ring->rptr_reg); | 374 | rptr = RREG32(ring->rptr_reg); |
@@ -821,18 +821,20 @@ static int radeon_debugfs_ring_info(struct seq_file *m, void *data) | |||
821 | return 0; | 821 | return 0; |
822 | } | 822 | } |
823 | 823 | ||
824 | static int radeon_ring_type_gfx_index = RADEON_RING_TYPE_GFX_INDEX; | 824 | static int radeon_gfx_index = RADEON_RING_TYPE_GFX_INDEX; |
825 | static int cayman_ring_type_cp1_index = CAYMAN_RING_TYPE_CP1_INDEX; | 825 | static int cayman_cp1_index = CAYMAN_RING_TYPE_CP1_INDEX; |
826 | static int cayman_ring_type_cp2_index = CAYMAN_RING_TYPE_CP2_INDEX; | 826 | static int cayman_cp2_index = CAYMAN_RING_TYPE_CP2_INDEX; |
827 | static int radeon_ring_type_dma1_index = R600_RING_TYPE_DMA_INDEX; | 827 | static int radeon_dma1_index = R600_RING_TYPE_DMA_INDEX; |
828 | static int radeon_ring_type_dma2_index = CAYMAN_RING_TYPE_DMA1_INDEX; | 828 | static int radeon_dma2_index = CAYMAN_RING_TYPE_DMA1_INDEX; |
829 | static int r600_uvd_index = R600_RING_TYPE_UVD_INDEX; | ||
829 | 830 | ||
830 | static struct drm_info_list radeon_debugfs_ring_info_list[] = { | 831 | static struct drm_info_list radeon_debugfs_ring_info_list[] = { |
831 | {"radeon_ring_gfx", radeon_debugfs_ring_info, 0, &radeon_ring_type_gfx_index}, | 832 | {"radeon_ring_gfx", radeon_debugfs_ring_info, 0, &radeon_gfx_index}, |
832 | {"radeon_ring_cp1", radeon_debugfs_ring_info, 0, &cayman_ring_type_cp1_index}, | 833 | {"radeon_ring_cp1", radeon_debugfs_ring_info, 0, &cayman_cp1_index}, |
833 | {"radeon_ring_cp2", radeon_debugfs_ring_info, 0, &cayman_ring_type_cp2_index}, | 834 | {"radeon_ring_cp2", radeon_debugfs_ring_info, 0, &cayman_cp2_index}, |
834 | {"radeon_ring_dma1", radeon_debugfs_ring_info, 0, &radeon_ring_type_dma1_index}, | 835 | {"radeon_ring_dma1", radeon_debugfs_ring_info, 0, &radeon_dma1_index}, |
835 | {"radeon_ring_dma2", radeon_debugfs_ring_info, 0, &radeon_ring_type_dma2_index}, | 836 | {"radeon_ring_dma2", radeon_debugfs_ring_info, 0, &radeon_dma2_index}, |
837 | {"radeon_ring_uvd", radeon_debugfs_ring_info, 0, &r600_uvd_index}, | ||
836 | }; | 838 | }; |
837 | 839 | ||
838 | static int radeon_debugfs_sa_info(struct seq_file *m, void *data) | 840 | static int radeon_debugfs_sa_info(struct seq_file *m, void *data) |
diff --git a/drivers/gpu/drm/radeon/radeon_test.c b/drivers/gpu/drm/radeon/radeon_test.c index fda09c9ea689..bbed4af8d0bc 100644 --- a/drivers/gpu/drm/radeon/radeon_test.c +++ b/drivers/gpu/drm/radeon/radeon_test.c | |||
@@ -252,6 +252,36 @@ void radeon_test_moves(struct radeon_device *rdev) | |||
252 | radeon_do_test_moves(rdev, RADEON_TEST_COPY_BLIT); | 252 | radeon_do_test_moves(rdev, RADEON_TEST_COPY_BLIT); |
253 | } | 253 | } |
254 | 254 | ||
255 | static int radeon_test_create_and_emit_fence(struct radeon_device *rdev, | ||
256 | struct radeon_ring *ring, | ||
257 | struct radeon_fence **fence) | ||
258 | { | ||
259 | int r; | ||
260 | |||
261 | if (ring->idx == R600_RING_TYPE_UVD_INDEX) { | ||
262 | r = radeon_uvd_get_create_msg(rdev, ring->idx, 1, NULL); | ||
263 | if (r) { | ||
264 | DRM_ERROR("Failed to get dummy create msg\n"); | ||
265 | return r; | ||
266 | } | ||
267 | |||
268 | r = radeon_uvd_get_destroy_msg(rdev, ring->idx, 1, fence); | ||
269 | if (r) { | ||
270 | DRM_ERROR("Failed to get dummy destroy msg\n"); | ||
271 | return r; | ||
272 | } | ||
273 | } else { | ||
274 | r = radeon_ring_lock(rdev, ring, 64); | ||
275 | if (r) { | ||
276 | DRM_ERROR("Failed to lock ring A %d\n", ring->idx); | ||
277 | return r; | ||
278 | } | ||
279 | radeon_fence_emit(rdev, fence, ring->idx); | ||
280 | radeon_ring_unlock_commit(rdev, ring); | ||
281 | } | ||
282 | return 0; | ||
283 | } | ||
284 | |||
255 | void radeon_test_ring_sync(struct radeon_device *rdev, | 285 | void radeon_test_ring_sync(struct radeon_device *rdev, |
256 | struct radeon_ring *ringA, | 286 | struct radeon_ring *ringA, |
257 | struct radeon_ring *ringB) | 287 | struct radeon_ring *ringB) |
@@ -272,21 +302,24 @@ void radeon_test_ring_sync(struct radeon_device *rdev, | |||
272 | goto out_cleanup; | 302 | goto out_cleanup; |
273 | } | 303 | } |
274 | radeon_semaphore_emit_wait(rdev, ringA->idx, semaphore); | 304 | radeon_semaphore_emit_wait(rdev, ringA->idx, semaphore); |
275 | r = radeon_fence_emit(rdev, &fence1, ringA->idx); | 305 | radeon_ring_unlock_commit(rdev, ringA); |
276 | if (r) { | 306 | |
277 | DRM_ERROR("Failed to emit fence 1\n"); | 307 | r = radeon_test_create_and_emit_fence(rdev, ringA, &fence1); |
278 | radeon_ring_unlock_undo(rdev, ringA); | 308 | if (r) |
279 | goto out_cleanup; | 309 | goto out_cleanup; |
280 | } | 310 | |
281 | radeon_semaphore_emit_wait(rdev, ringA->idx, semaphore); | 311 | r = radeon_ring_lock(rdev, ringA, 64); |
282 | r = radeon_fence_emit(rdev, &fence2, ringA->idx); | ||
283 | if (r) { | 312 | if (r) { |
284 | DRM_ERROR("Failed to emit fence 2\n"); | 313 | DRM_ERROR("Failed to lock ring A %d\n", ringA->idx); |
285 | radeon_ring_unlock_undo(rdev, ringA); | ||
286 | goto out_cleanup; | 314 | goto out_cleanup; |
287 | } | 315 | } |
316 | radeon_semaphore_emit_wait(rdev, ringA->idx, semaphore); | ||
288 | radeon_ring_unlock_commit(rdev, ringA); | 317 | radeon_ring_unlock_commit(rdev, ringA); |
289 | 318 | ||
319 | r = radeon_test_create_and_emit_fence(rdev, ringA, &fence2); | ||
320 | if (r) | ||
321 | goto out_cleanup; | ||
322 | |||
290 | mdelay(1000); | 323 | mdelay(1000); |
291 | 324 | ||
292 | if (radeon_fence_signaled(fence1)) { | 325 | if (radeon_fence_signaled(fence1)) { |
@@ -364,27 +397,22 @@ static void radeon_test_ring_sync2(struct radeon_device *rdev, | |||
364 | goto out_cleanup; | 397 | goto out_cleanup; |
365 | } | 398 | } |
366 | radeon_semaphore_emit_wait(rdev, ringA->idx, semaphore); | 399 | radeon_semaphore_emit_wait(rdev, ringA->idx, semaphore); |
367 | r = radeon_fence_emit(rdev, &fenceA, ringA->idx); | ||
368 | if (r) { | ||
369 | DRM_ERROR("Failed to emit sync fence 1\n"); | ||
370 | radeon_ring_unlock_undo(rdev, ringA); | ||
371 | goto out_cleanup; | ||
372 | } | ||
373 | radeon_ring_unlock_commit(rdev, ringA); | 400 | radeon_ring_unlock_commit(rdev, ringA); |
374 | 401 | ||
402 | r = radeon_test_create_and_emit_fence(rdev, ringA, &fenceA); | ||
403 | if (r) | ||
404 | goto out_cleanup; | ||
405 | |||
375 | r = radeon_ring_lock(rdev, ringB, 64); | 406 | r = radeon_ring_lock(rdev, ringB, 64); |
376 | if (r) { | 407 | if (r) { |
377 | DRM_ERROR("Failed to lock ring B %d\n", ringB->idx); | 408 | DRM_ERROR("Failed to lock ring B %d\n", ringB->idx); |
378 | goto out_cleanup; | 409 | goto out_cleanup; |
379 | } | 410 | } |
380 | radeon_semaphore_emit_wait(rdev, ringB->idx, semaphore); | 411 | radeon_semaphore_emit_wait(rdev, ringB->idx, semaphore); |
381 | r = radeon_fence_emit(rdev, &fenceB, ringB->idx); | ||
382 | if (r) { | ||
383 | DRM_ERROR("Failed to create sync fence 2\n"); | ||
384 | radeon_ring_unlock_undo(rdev, ringB); | ||
385 | goto out_cleanup; | ||
386 | } | ||
387 | radeon_ring_unlock_commit(rdev, ringB); | 412 | radeon_ring_unlock_commit(rdev, ringB); |
413 | r = radeon_test_create_and_emit_fence(rdev, ringB, &fenceB); | ||
414 | if (r) | ||
415 | goto out_cleanup; | ||
388 | 416 | ||
389 | mdelay(1000); | 417 | mdelay(1000); |
390 | 418 | ||
@@ -393,7 +421,7 @@ static void radeon_test_ring_sync2(struct radeon_device *rdev, | |||
393 | goto out_cleanup; | 421 | goto out_cleanup; |
394 | } | 422 | } |
395 | if (radeon_fence_signaled(fenceB)) { | 423 | if (radeon_fence_signaled(fenceB)) { |
396 | DRM_ERROR("Fence A signaled without waiting for semaphore.\n"); | 424 | DRM_ERROR("Fence B signaled without waiting for semaphore.\n"); |
397 | goto out_cleanup; | 425 | goto out_cleanup; |
398 | } | 426 | } |
399 | 427 | ||
diff --git a/drivers/gpu/drm/radeon/radeon_uvd.c b/drivers/gpu/drm/radeon/radeon_uvd.c new file mode 100644 index 000000000000..05a192e95e5d --- /dev/null +++ b/drivers/gpu/drm/radeon/radeon_uvd.c | |||
@@ -0,0 +1,664 @@ | |||
1 | /* | ||
2 | * Copyright 2011 Advanced Micro Devices, Inc. | ||
3 | * All Rights Reserved. | ||
4 | * | ||
5 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
6 | * copy of this software and associated documentation files (the | ||
7 | * "Software"), to deal in the Software without restriction, including | ||
8 | * without limitation the rights to use, copy, modify, merge, publish, | ||
9 | * distribute, sub license, and/or sell copies of the Software, and to | ||
10 | * permit persons to whom the Software is furnished to do so, subject to | ||
11 | * the following conditions: | ||
12 | * | ||
13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
14 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
15 | * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL | ||
16 | * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, | ||
17 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR | ||
18 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE | ||
19 | * USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
20 | * | ||
21 | * The above copyright notice and this permission notice (including the | ||
22 | * next paragraph) shall be included in all copies or substantial portions | ||
23 | * of the Software. | ||
24 | * | ||
25 | */ | ||
26 | /* | ||
27 | * Authors: | ||
28 | * Christian König <deathsimple@vodafone.de> | ||
29 | */ | ||
30 | |||
31 | #include <linux/firmware.h> | ||
32 | #include <linux/module.h> | ||
33 | #include <drm/drmP.h> | ||
34 | #include <drm/drm.h> | ||
35 | |||
36 | #include "radeon.h" | ||
37 | #include "r600d.h" | ||
38 | |||
39 | /* Firmware Names */ | ||
40 | #define FIRMWARE_RV710 "radeon/RV710_uvd.bin" | ||
41 | #define FIRMWARE_CYPRESS "radeon/CYPRESS_uvd.bin" | ||
42 | #define FIRMWARE_SUMO "radeon/SUMO_uvd.bin" | ||
43 | #define FIRMWARE_TAHITI "radeon/TAHITI_uvd.bin" | ||
44 | |||
45 | MODULE_FIRMWARE(FIRMWARE_RV710); | ||
46 | MODULE_FIRMWARE(FIRMWARE_CYPRESS); | ||
47 | MODULE_FIRMWARE(FIRMWARE_SUMO); | ||
48 | MODULE_FIRMWARE(FIRMWARE_TAHITI); | ||
49 | |||
50 | int radeon_uvd_init(struct radeon_device *rdev) | ||
51 | { | ||
52 | struct platform_device *pdev; | ||
53 | unsigned long bo_size; | ||
54 | const char *fw_name; | ||
55 | int i, r; | ||
56 | |||
57 | pdev = platform_device_register_simple("radeon_uvd", 0, NULL, 0); | ||
58 | r = IS_ERR(pdev); | ||
59 | if (r) { | ||
60 | dev_err(rdev->dev, "radeon_uvd: Failed to register firmware\n"); | ||
61 | return -EINVAL; | ||
62 | } | ||
63 | |||
64 | switch (rdev->family) { | ||
65 | case CHIP_RV710: | ||
66 | case CHIP_RV730: | ||
67 | case CHIP_RV740: | ||
68 | fw_name = FIRMWARE_RV710; | ||
69 | break; | ||
70 | |||
71 | case CHIP_CYPRESS: | ||
72 | case CHIP_HEMLOCK: | ||
73 | case CHIP_JUNIPER: | ||
74 | case CHIP_REDWOOD: | ||
75 | case CHIP_CEDAR: | ||
76 | fw_name = FIRMWARE_CYPRESS; | ||
77 | break; | ||
78 | |||
79 | case CHIP_SUMO: | ||
80 | case CHIP_SUMO2: | ||
81 | case CHIP_PALM: | ||
82 | case CHIP_CAYMAN: | ||
83 | case CHIP_BARTS: | ||
84 | case CHIP_TURKS: | ||
85 | case CHIP_CAICOS: | ||
86 | fw_name = FIRMWARE_SUMO; | ||
87 | break; | ||
88 | |||
89 | case CHIP_TAHITI: | ||
90 | case CHIP_VERDE: | ||
91 | case CHIP_PITCAIRN: | ||
92 | case CHIP_ARUBA: | ||
93 | fw_name = FIRMWARE_TAHITI; | ||
94 | break; | ||
95 | |||
96 | default: | ||
97 | return -EINVAL; | ||
98 | } | ||
99 | |||
100 | r = request_firmware(&rdev->uvd_fw, fw_name, &pdev->dev); | ||
101 | if (r) { | ||
102 | dev_err(rdev->dev, "radeon_uvd: Can't load firmware \"%s\"\n", | ||
103 | fw_name); | ||
104 | platform_device_unregister(pdev); | ||
105 | return r; | ||
106 | } | ||
107 | |||
108 | platform_device_unregister(pdev); | ||
109 | |||
110 | bo_size = RADEON_GPU_PAGE_ALIGN(rdev->uvd_fw->size + 4) + | ||
111 | RADEON_UVD_STACK_SIZE + RADEON_UVD_HEAP_SIZE; | ||
112 | r = radeon_bo_create(rdev, bo_size, PAGE_SIZE, true, | ||
113 | RADEON_GEM_DOMAIN_VRAM, NULL, &rdev->uvd.vcpu_bo); | ||
114 | if (r) { | ||
115 | dev_err(rdev->dev, "(%d) failed to allocate UVD bo\n", r); | ||
116 | return r; | ||
117 | } | ||
118 | |||
119 | r = radeon_uvd_resume(rdev); | ||
120 | if (r) | ||
121 | return r; | ||
122 | |||
123 | memset(rdev->uvd.cpu_addr, 0, bo_size); | ||
124 | memcpy(rdev->uvd.cpu_addr, rdev->uvd_fw->data, rdev->uvd_fw->size); | ||
125 | |||
126 | r = radeon_uvd_suspend(rdev); | ||
127 | if (r) | ||
128 | return r; | ||
129 | |||
130 | for (i = 0; i < RADEON_MAX_UVD_HANDLES; ++i) { | ||
131 | atomic_set(&rdev->uvd.handles[i], 0); | ||
132 | rdev->uvd.filp[i] = NULL; | ||
133 | } | ||
134 | |||
135 | return 0; | ||
136 | } | ||
137 | |||
138 | void radeon_uvd_fini(struct radeon_device *rdev) | ||
139 | { | ||
140 | radeon_uvd_suspend(rdev); | ||
141 | radeon_bo_unref(&rdev->uvd.vcpu_bo); | ||
142 | } | ||
143 | |||
144 | int radeon_uvd_suspend(struct radeon_device *rdev) | ||
145 | { | ||
146 | int r; | ||
147 | |||
148 | if (rdev->uvd.vcpu_bo == NULL) | ||
149 | return 0; | ||
150 | |||
151 | r = radeon_bo_reserve(rdev->uvd.vcpu_bo, false); | ||
152 | if (!r) { | ||
153 | radeon_bo_kunmap(rdev->uvd.vcpu_bo); | ||
154 | radeon_bo_unpin(rdev->uvd.vcpu_bo); | ||
155 | radeon_bo_unreserve(rdev->uvd.vcpu_bo); | ||
156 | } | ||
157 | return r; | ||
158 | } | ||
159 | |||
160 | int radeon_uvd_resume(struct radeon_device *rdev) | ||
161 | { | ||
162 | int r; | ||
163 | |||
164 | if (rdev->uvd.vcpu_bo == NULL) | ||
165 | return -EINVAL; | ||
166 | |||
167 | r = radeon_bo_reserve(rdev->uvd.vcpu_bo, false); | ||
168 | if (r) { | ||
169 | radeon_bo_unref(&rdev->uvd.vcpu_bo); | ||
170 | dev_err(rdev->dev, "(%d) failed to reserve UVD bo\n", r); | ||
171 | return r; | ||
172 | } | ||
173 | |||
174 | r = radeon_bo_pin(rdev->uvd.vcpu_bo, RADEON_GEM_DOMAIN_VRAM, | ||
175 | &rdev->uvd.gpu_addr); | ||
176 | if (r) { | ||
177 | radeon_bo_unreserve(rdev->uvd.vcpu_bo); | ||
178 | radeon_bo_unref(&rdev->uvd.vcpu_bo); | ||
179 | dev_err(rdev->dev, "(%d) UVD bo pin failed\n", r); | ||
180 | return r; | ||
181 | } | ||
182 | |||
183 | r = radeon_bo_kmap(rdev->uvd.vcpu_bo, &rdev->uvd.cpu_addr); | ||
184 | if (r) { | ||
185 | dev_err(rdev->dev, "(%d) UVD map failed\n", r); | ||
186 | return r; | ||
187 | } | ||
188 | |||
189 | radeon_bo_unreserve(rdev->uvd.vcpu_bo); | ||
190 | |||
191 | return 0; | ||
192 | } | ||
193 | |||
194 | void radeon_uvd_force_into_uvd_segment(struct radeon_bo *rbo) | ||
195 | { | ||
196 | rbo->placement.fpfn = 0 >> PAGE_SHIFT; | ||
197 | rbo->placement.lpfn = (256 * 1024 * 1024) >> PAGE_SHIFT; | ||
198 | } | ||
199 | |||
200 | void radeon_uvd_free_handles(struct radeon_device *rdev, struct drm_file *filp) | ||
201 | { | ||
202 | int i, r; | ||
203 | for (i = 0; i < RADEON_MAX_UVD_HANDLES; ++i) { | ||
204 | if (rdev->uvd.filp[i] == filp) { | ||
205 | uint32_t handle = atomic_read(&rdev->uvd.handles[i]); | ||
206 | struct radeon_fence *fence; | ||
207 | |||
208 | r = radeon_uvd_get_destroy_msg(rdev, | ||
209 | R600_RING_TYPE_UVD_INDEX, handle, &fence); | ||
210 | if (r) { | ||
211 | DRM_ERROR("Error destroying UVD (%d)!\n", r); | ||
212 | continue; | ||
213 | } | ||
214 | |||
215 | radeon_fence_wait(fence, false); | ||
216 | radeon_fence_unref(&fence); | ||
217 | |||
218 | rdev->uvd.filp[i] = NULL; | ||
219 | atomic_set(&rdev->uvd.handles[i], 0); | ||
220 | } | ||
221 | } | ||
222 | } | ||
223 | |||
224 | static int radeon_uvd_cs_msg_decode(uint32_t *msg, unsigned buf_sizes[]) | ||
225 | { | ||
226 | unsigned stream_type = msg[4]; | ||
227 | unsigned width = msg[6]; | ||
228 | unsigned height = msg[7]; | ||
229 | unsigned dpb_size = msg[9]; | ||
230 | unsigned pitch = msg[28]; | ||
231 | |||
232 | unsigned width_in_mb = width / 16; | ||
233 | unsigned height_in_mb = ALIGN(height / 16, 2); | ||
234 | |||
235 | unsigned image_size, tmp, min_dpb_size; | ||
236 | |||
237 | image_size = width * height; | ||
238 | image_size += image_size / 2; | ||
239 | image_size = ALIGN(image_size, 1024); | ||
240 | |||
241 | switch (stream_type) { | ||
242 | case 0: /* H264 */ | ||
243 | |||
244 | /* reference picture buffer */ | ||
245 | min_dpb_size = image_size * 17; | ||
246 | |||
247 | /* macroblock context buffer */ | ||
248 | min_dpb_size += width_in_mb * height_in_mb * 17 * 192; | ||
249 | |||
250 | /* IT surface buffer */ | ||
251 | min_dpb_size += width_in_mb * height_in_mb * 32; | ||
252 | break; | ||
253 | |||
254 | case 1: /* VC1 */ | ||
255 | |||
256 | /* reference picture buffer */ | ||
257 | min_dpb_size = image_size * 3; | ||
258 | |||
259 | /* CONTEXT_BUFFER */ | ||
260 | min_dpb_size += width_in_mb * height_in_mb * 128; | ||
261 | |||
262 | /* IT surface buffer */ | ||
263 | min_dpb_size += width_in_mb * 64; | ||
264 | |||
265 | /* DB surface buffer */ | ||
266 | min_dpb_size += width_in_mb * 128; | ||
267 | |||
268 | /* BP */ | ||
269 | tmp = max(width_in_mb, height_in_mb); | ||
270 | min_dpb_size += ALIGN(tmp * 7 * 16, 64); | ||
271 | break; | ||
272 | |||
273 | case 3: /* MPEG2 */ | ||
274 | |||
275 | /* reference picture buffer */ | ||
276 | min_dpb_size = image_size * 3; | ||
277 | break; | ||
278 | |||
279 | case 4: /* MPEG4 */ | ||
280 | |||
281 | /* reference picture buffer */ | ||
282 | min_dpb_size = image_size * 3; | ||
283 | |||
284 | /* CM */ | ||
285 | min_dpb_size += width_in_mb * height_in_mb * 64; | ||
286 | |||
287 | /* IT surface buffer */ | ||
288 | min_dpb_size += ALIGN(width_in_mb * height_in_mb * 32, 64); | ||
289 | break; | ||
290 | |||
291 | default: | ||
292 | DRM_ERROR("UVD codec not handled %d!\n", stream_type); | ||
293 | return -EINVAL; | ||
294 | } | ||
295 | |||
296 | if (width > pitch) { | ||
297 | DRM_ERROR("Invalid UVD decoding target pitch!\n"); | ||
298 | return -EINVAL; | ||
299 | } | ||
300 | |||
301 | if (dpb_size < min_dpb_size) { | ||
302 | DRM_ERROR("Invalid dpb_size in UVD message (%d / %d)!\n", | ||
303 | dpb_size, min_dpb_size); | ||
304 | return -EINVAL; | ||
305 | } | ||
306 | |||
307 | buf_sizes[0x1] = dpb_size; | ||
308 | buf_sizes[0x2] = image_size; | ||
309 | return 0; | ||
310 | } | ||
311 | |||
312 | static int radeon_uvd_cs_msg(struct radeon_cs_parser *p, struct radeon_bo *bo, | ||
313 | unsigned offset, unsigned buf_sizes[]) | ||
314 | { | ||
315 | int32_t *msg, msg_type, handle; | ||
316 | void *ptr; | ||
317 | |||
318 | int i, r; | ||
319 | |||
320 | if (offset & 0x3F) { | ||
321 | DRM_ERROR("UVD messages must be 64 byte aligned!\n"); | ||
322 | return -EINVAL; | ||
323 | } | ||
324 | |||
325 | r = radeon_bo_kmap(bo, &ptr); | ||
326 | if (r) | ||
327 | return r; | ||
328 | |||
329 | msg = ptr + offset; | ||
330 | |||
331 | msg_type = msg[1]; | ||
332 | handle = msg[2]; | ||
333 | |||
334 | if (handle == 0) { | ||
335 | DRM_ERROR("Invalid UVD handle!\n"); | ||
336 | return -EINVAL; | ||
337 | } | ||
338 | |||
339 | if (msg_type == 1) { | ||
340 | /* it's a decode msg, calc buffer sizes */ | ||
341 | r = radeon_uvd_cs_msg_decode(msg, buf_sizes); | ||
342 | radeon_bo_kunmap(bo); | ||
343 | if (r) | ||
344 | return r; | ||
345 | |||
346 | } else if (msg_type == 2) { | ||
347 | /* it's a destroy msg, free the handle */ | ||
348 | for (i = 0; i < RADEON_MAX_UVD_HANDLES; ++i) | ||
349 | atomic_cmpxchg(&p->rdev->uvd.handles[i], handle, 0); | ||
350 | radeon_bo_kunmap(bo); | ||
351 | return 0; | ||
352 | } else { | ||
353 | /* it's a create msg, no special handling needed */ | ||
354 | radeon_bo_kunmap(bo); | ||
355 | } | ||
356 | |||
357 | /* create or decode, validate the handle */ | ||
358 | for (i = 0; i < RADEON_MAX_UVD_HANDLES; ++i) { | ||
359 | if (atomic_read(&p->rdev->uvd.handles[i]) == handle) | ||
360 | return 0; | ||
361 | } | ||
362 | |||
363 | /* handle not found try to alloc a new one */ | ||
364 | for (i = 0; i < RADEON_MAX_UVD_HANDLES; ++i) { | ||
365 | if (!atomic_cmpxchg(&p->rdev->uvd.handles[i], 0, handle)) { | ||
366 | p->rdev->uvd.filp[i] = p->filp; | ||
367 | return 0; | ||
368 | } | ||
369 | } | ||
370 | |||
371 | DRM_ERROR("No more free UVD handles!\n"); | ||
372 | return -EINVAL; | ||
373 | } | ||
374 | |||
375 | static int radeon_uvd_cs_reloc(struct radeon_cs_parser *p, | ||
376 | int data0, int data1, | ||
377 | unsigned buf_sizes[]) | ||
378 | { | ||
379 | struct radeon_cs_chunk *relocs_chunk; | ||
380 | struct radeon_cs_reloc *reloc; | ||
381 | unsigned idx, cmd, offset; | ||
382 | uint64_t start, end; | ||
383 | int r; | ||
384 | |||
385 | relocs_chunk = &p->chunks[p->chunk_relocs_idx]; | ||
386 | offset = radeon_get_ib_value(p, data0); | ||
387 | idx = radeon_get_ib_value(p, data1); | ||
388 | if (idx >= relocs_chunk->length_dw) { | ||
389 | DRM_ERROR("Relocs at %d after relocations chunk end %d !\n", | ||
390 | idx, relocs_chunk->length_dw); | ||
391 | return -EINVAL; | ||
392 | } | ||
393 | |||
394 | reloc = p->relocs_ptr[(idx / 4)]; | ||
395 | start = reloc->lobj.gpu_offset; | ||
396 | end = start + radeon_bo_size(reloc->robj); | ||
397 | start += offset; | ||
398 | |||
399 | p->ib.ptr[data0] = start & 0xFFFFFFFF; | ||
400 | p->ib.ptr[data1] = start >> 32; | ||
401 | |||
402 | cmd = radeon_get_ib_value(p, p->idx) >> 1; | ||
403 | |||
404 | if (cmd < 0x4) { | ||
405 | if ((end - start) < buf_sizes[cmd]) { | ||
406 | DRM_ERROR("buffer to small (%d / %d)!\n", | ||
407 | (unsigned)(end - start), buf_sizes[cmd]); | ||
408 | return -EINVAL; | ||
409 | } | ||
410 | |||
411 | } else if (cmd != 0x100) { | ||
412 | DRM_ERROR("invalid UVD command %X!\n", cmd); | ||
413 | return -EINVAL; | ||
414 | } | ||
415 | |||
416 | if (cmd == 0) { | ||
417 | if (end & 0xFFFFFFFFF0000000) { | ||
418 | DRM_ERROR("msg buffer %LX-%LX out of 256MB segment!\n", | ||
419 | start, end); | ||
420 | return -EINVAL; | ||
421 | } | ||
422 | |||
423 | r = radeon_uvd_cs_msg(p, reloc->robj, offset, buf_sizes); | ||
424 | if (r) | ||
425 | return r; | ||
426 | } | ||
427 | |||
428 | if ((start & 0xFFFFFFFFF0000000) != (end & 0xFFFFFFFFF0000000)) { | ||
429 | DRM_ERROR("reloc %LX-%LX crossing 256MB boundary!\n", | ||
430 | start, end); | ||
431 | return -EINVAL; | ||
432 | } | ||
433 | |||
434 | return 0; | ||
435 | } | ||
436 | |||
437 | static int radeon_uvd_cs_reg(struct radeon_cs_parser *p, | ||
438 | struct radeon_cs_packet *pkt, | ||
439 | int *data0, int *data1, | ||
440 | unsigned buf_sizes[]) | ||
441 | { | ||
442 | int i, r; | ||
443 | |||
444 | p->idx++; | ||
445 | for (i = 0; i <= pkt->count; ++i) { | ||
446 | switch (pkt->reg + i*4) { | ||
447 | case UVD_GPCOM_VCPU_DATA0: | ||
448 | *data0 = p->idx; | ||
449 | break; | ||
450 | case UVD_GPCOM_VCPU_DATA1: | ||
451 | *data1 = p->idx; | ||
452 | break; | ||
453 | case UVD_GPCOM_VCPU_CMD: | ||
454 | r = radeon_uvd_cs_reloc(p, *data0, *data1, buf_sizes); | ||
455 | if (r) | ||
456 | return r; | ||
457 | break; | ||
458 | case UVD_ENGINE_CNTL: | ||
459 | break; | ||
460 | default: | ||
461 | DRM_ERROR("Invalid reg 0x%X!\n", | ||
462 | pkt->reg + i*4); | ||
463 | return -EINVAL; | ||
464 | } | ||
465 | p->idx++; | ||
466 | } | ||
467 | return 0; | ||
468 | } | ||
469 | |||
470 | int radeon_uvd_cs_parse(struct radeon_cs_parser *p) | ||
471 | { | ||
472 | struct radeon_cs_packet pkt; | ||
473 | int r, data0 = 0, data1 = 0; | ||
474 | |||
475 | /* minimum buffer sizes */ | ||
476 | unsigned buf_sizes[] = { | ||
477 | [0x00000000] = 2048, | ||
478 | [0x00000001] = 32 * 1024 * 1024, | ||
479 | [0x00000002] = 2048 * 1152 * 3, | ||
480 | [0x00000003] = 2048, | ||
481 | }; | ||
482 | |||
483 | if (p->chunks[p->chunk_ib_idx].length_dw % 16) { | ||
484 | DRM_ERROR("UVD IB length (%d) not 16 dwords aligned!\n", | ||
485 | p->chunks[p->chunk_ib_idx].length_dw); | ||
486 | return -EINVAL; | ||
487 | } | ||
488 | |||
489 | if (p->chunk_relocs_idx == -1) { | ||
490 | DRM_ERROR("No relocation chunk !\n"); | ||
491 | return -EINVAL; | ||
492 | } | ||
493 | |||
494 | |||
495 | do { | ||
496 | r = radeon_cs_packet_parse(p, &pkt, p->idx); | ||
497 | if (r) | ||
498 | return r; | ||
499 | switch (pkt.type) { | ||
500 | case RADEON_PACKET_TYPE0: | ||
501 | r = radeon_uvd_cs_reg(p, &pkt, &data0, | ||
502 | &data1, buf_sizes); | ||
503 | if (r) | ||
504 | return r; | ||
505 | break; | ||
506 | case RADEON_PACKET_TYPE2: | ||
507 | p->idx += pkt.count + 2; | ||
508 | break; | ||
509 | default: | ||
510 | DRM_ERROR("Unknown packet type %d !\n", pkt.type); | ||
511 | return -EINVAL; | ||
512 | } | ||
513 | } while (p->idx < p->chunks[p->chunk_ib_idx].length_dw); | ||
514 | return 0; | ||
515 | } | ||
516 | |||
517 | static int radeon_uvd_send_msg(struct radeon_device *rdev, | ||
518 | int ring, struct radeon_bo *bo, | ||
519 | struct radeon_fence **fence) | ||
520 | { | ||
521 | struct ttm_validate_buffer tv; | ||
522 | struct list_head head; | ||
523 | struct radeon_ib ib; | ||
524 | uint64_t addr; | ||
525 | int i, r; | ||
526 | |||
527 | memset(&tv, 0, sizeof(tv)); | ||
528 | tv.bo = &bo->tbo; | ||
529 | |||
530 | INIT_LIST_HEAD(&head); | ||
531 | list_add(&tv.head, &head); | ||
532 | |||
533 | r = ttm_eu_reserve_buffers(&head); | ||
534 | if (r) | ||
535 | return r; | ||
536 | |||
537 | radeon_ttm_placement_from_domain(bo, RADEON_GEM_DOMAIN_VRAM); | ||
538 | radeon_uvd_force_into_uvd_segment(bo); | ||
539 | |||
540 | r = ttm_bo_validate(&bo->tbo, &bo->placement, true, false); | ||
541 | if (r) { | ||
542 | ttm_eu_backoff_reservation(&head); | ||
543 | return r; | ||
544 | } | ||
545 | |||
546 | r = radeon_ib_get(rdev, ring, &ib, NULL, 16); | ||
547 | if (r) { | ||
548 | ttm_eu_backoff_reservation(&head); | ||
549 | return r; | ||
550 | } | ||
551 | |||
552 | addr = radeon_bo_gpu_offset(bo); | ||
553 | ib.ptr[0] = PACKET0(UVD_GPCOM_VCPU_DATA0, 0); | ||
554 | ib.ptr[1] = addr; | ||
555 | ib.ptr[2] = PACKET0(UVD_GPCOM_VCPU_DATA1, 0); | ||
556 | ib.ptr[3] = addr >> 32; | ||
557 | ib.ptr[4] = PACKET0(UVD_GPCOM_VCPU_CMD, 0); | ||
558 | ib.ptr[5] = 0; | ||
559 | for (i = 6; i < 16; ++i) | ||
560 | ib.ptr[i] = PACKET2(0); | ||
561 | ib.length_dw = 16; | ||
562 | |||
563 | r = radeon_ib_schedule(rdev, &ib, NULL); | ||
564 | if (r) { | ||
565 | ttm_eu_backoff_reservation(&head); | ||
566 | return r; | ||
567 | } | ||
568 | ttm_eu_fence_buffer_objects(&head, ib.fence); | ||
569 | |||
570 | if (fence) | ||
571 | *fence = radeon_fence_ref(ib.fence); | ||
572 | |||
573 | radeon_ib_free(rdev, &ib); | ||
574 | radeon_bo_unref(&bo); | ||
575 | return 0; | ||
576 | } | ||
577 | |||
578 | /* multiple fence commands without any stream commands in between can | ||
579 | crash the vcpu so just try to emmit a dummy create/destroy msg to | ||
580 | avoid this */ | ||
581 | int radeon_uvd_get_create_msg(struct radeon_device *rdev, int ring, | ||
582 | uint32_t handle, struct radeon_fence **fence) | ||
583 | { | ||
584 | struct radeon_bo *bo; | ||
585 | uint32_t *msg; | ||
586 | int r, i; | ||
587 | |||
588 | r = radeon_bo_create(rdev, 1024, PAGE_SIZE, true, | ||
589 | RADEON_GEM_DOMAIN_VRAM, NULL, &bo); | ||
590 | if (r) | ||
591 | return r; | ||
592 | |||
593 | r = radeon_bo_reserve(bo, false); | ||
594 | if (r) { | ||
595 | radeon_bo_unref(&bo); | ||
596 | return r; | ||
597 | } | ||
598 | |||
599 | r = radeon_bo_kmap(bo, (void **)&msg); | ||
600 | if (r) { | ||
601 | radeon_bo_unreserve(bo); | ||
602 | radeon_bo_unref(&bo); | ||
603 | return r; | ||
604 | } | ||
605 | |||
606 | /* stitch together an UVD create msg */ | ||
607 | msg[0] = 0x00000de4; | ||
608 | msg[1] = 0x00000000; | ||
609 | msg[2] = handle; | ||
610 | msg[3] = 0x00000000; | ||
611 | msg[4] = 0x00000000; | ||
612 | msg[5] = 0x00000000; | ||
613 | msg[6] = 0x00000000; | ||
614 | msg[7] = 0x00000780; | ||
615 | msg[8] = 0x00000440; | ||
616 | msg[9] = 0x00000000; | ||
617 | msg[10] = 0x01b37000; | ||
618 | for (i = 11; i < 1024; ++i) | ||
619 | msg[i] = 0x0; | ||
620 | |||
621 | radeon_bo_kunmap(bo); | ||
622 | radeon_bo_unreserve(bo); | ||
623 | |||
624 | return radeon_uvd_send_msg(rdev, ring, bo, fence); | ||
625 | } | ||
626 | |||
627 | int radeon_uvd_get_destroy_msg(struct radeon_device *rdev, int ring, | ||
628 | uint32_t handle, struct radeon_fence **fence) | ||
629 | { | ||
630 | struct radeon_bo *bo; | ||
631 | uint32_t *msg; | ||
632 | int r, i; | ||
633 | |||
634 | r = radeon_bo_create(rdev, 1024, PAGE_SIZE, true, | ||
635 | RADEON_GEM_DOMAIN_VRAM, NULL, &bo); | ||
636 | if (r) | ||
637 | return r; | ||
638 | |||
639 | r = radeon_bo_reserve(bo, false); | ||
640 | if (r) { | ||
641 | radeon_bo_unref(&bo); | ||
642 | return r; | ||
643 | } | ||
644 | |||
645 | r = radeon_bo_kmap(bo, (void **)&msg); | ||
646 | if (r) { | ||
647 | radeon_bo_unreserve(bo); | ||
648 | radeon_bo_unref(&bo); | ||
649 | return r; | ||
650 | } | ||
651 | |||
652 | /* stitch together an UVD destroy msg */ | ||
653 | msg[0] = 0x00000de4; | ||
654 | msg[1] = 0x00000002; | ||
655 | msg[2] = handle; | ||
656 | msg[3] = 0x00000000; | ||
657 | for (i = 4; i < 1024; ++i) | ||
658 | msg[i] = 0x0; | ||
659 | |||
660 | radeon_bo_kunmap(bo); | ||
661 | radeon_bo_unreserve(bo); | ||
662 | |||
663 | return radeon_uvd_send_msg(rdev, ring, bo, fence); | ||
664 | } | ||
diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c index d4d9be17cfb9..a47e7b903cbc 100644 --- a/drivers/gpu/drm/radeon/rv770.c +++ b/drivers/gpu/drm/radeon/rv770.c | |||
@@ -68,6 +68,105 @@ u32 rv770_get_xclk(struct radeon_device *rdev) | |||
68 | return reference_clock; | 68 | return reference_clock; |
69 | } | 69 | } |
70 | 70 | ||
71 | int rv770_uvd_resume(struct radeon_device *rdev) | ||
72 | { | ||
73 | uint64_t addr; | ||
74 | uint32_t chip_id, size; | ||
75 | int r; | ||
76 | |||
77 | r = radeon_uvd_resume(rdev); | ||
78 | if (r) | ||
79 | return r; | ||
80 | |||
81 | /* programm the VCPU memory controller bits 0-27 */ | ||
82 | addr = rdev->uvd.gpu_addr >> 3; | ||
83 | size = RADEON_GPU_PAGE_ALIGN(rdev->uvd_fw->size + 4) >> 3; | ||
84 | WREG32(UVD_VCPU_CACHE_OFFSET0, addr); | ||
85 | WREG32(UVD_VCPU_CACHE_SIZE0, size); | ||
86 | |||
87 | addr += size; | ||
88 | size = RADEON_UVD_STACK_SIZE >> 3; | ||
89 | WREG32(UVD_VCPU_CACHE_OFFSET1, addr); | ||
90 | WREG32(UVD_VCPU_CACHE_SIZE1, size); | ||
91 | |||
92 | addr += size; | ||
93 | size = RADEON_UVD_HEAP_SIZE >> 3; | ||
94 | WREG32(UVD_VCPU_CACHE_OFFSET2, addr); | ||
95 | WREG32(UVD_VCPU_CACHE_SIZE2, size); | ||
96 | |||
97 | /* bits 28-31 */ | ||
98 | addr = (rdev->uvd.gpu_addr >> 28) & 0xF; | ||
99 | WREG32(UVD_LMI_ADDR_EXT, (addr << 12) | (addr << 0)); | ||
100 | |||
101 | /* bits 32-39 */ | ||
102 | addr = (rdev->uvd.gpu_addr >> 32) & 0xFF; | ||
103 | WREG32(UVD_LMI_EXT40_ADDR, addr | (0x9 << 16) | (0x1 << 31)); | ||
104 | |||
105 | /* tell firmware which hardware it is running on */ | ||
106 | switch (rdev->family) { | ||
107 | default: | ||
108 | return -EINVAL; | ||
109 | case CHIP_RV710: | ||
110 | chip_id = 0x01000005; | ||
111 | break; | ||
112 | case CHIP_RV730: | ||
113 | chip_id = 0x01000006; | ||
114 | break; | ||
115 | case CHIP_RV740: | ||
116 | chip_id = 0x01000007; | ||
117 | break; | ||
118 | case CHIP_CYPRESS: | ||
119 | case CHIP_HEMLOCK: | ||
120 | chip_id = 0x01000008; | ||
121 | break; | ||
122 | case CHIP_JUNIPER: | ||
123 | chip_id = 0x01000009; | ||
124 | break; | ||
125 | case CHIP_REDWOOD: | ||
126 | chip_id = 0x0100000a; | ||
127 | break; | ||
128 | case CHIP_CEDAR: | ||
129 | chip_id = 0x0100000b; | ||
130 | break; | ||
131 | case CHIP_SUMO: | ||
132 | chip_id = 0x0100000c; | ||
133 | break; | ||
134 | case CHIP_SUMO2: | ||
135 | chip_id = 0x0100000d; | ||
136 | break; | ||
137 | case CHIP_PALM: | ||
138 | chip_id = 0x0100000e; | ||
139 | break; | ||
140 | case CHIP_CAYMAN: | ||
141 | chip_id = 0x0100000f; | ||
142 | break; | ||
143 | case CHIP_BARTS: | ||
144 | chip_id = 0x01000010; | ||
145 | break; | ||
146 | case CHIP_TURKS: | ||
147 | chip_id = 0x01000011; | ||
148 | break; | ||
149 | case CHIP_CAICOS: | ||
150 | chip_id = 0x01000012; | ||
151 | break; | ||
152 | case CHIP_TAHITI: | ||
153 | chip_id = 0x01000014; | ||
154 | break; | ||
155 | case CHIP_VERDE: | ||
156 | chip_id = 0x01000015; | ||
157 | break; | ||
158 | case CHIP_PITCAIRN: | ||
159 | chip_id = 0x01000016; | ||
160 | break; | ||
161 | case CHIP_ARUBA: | ||
162 | chip_id = 0x01000017; | ||
163 | break; | ||
164 | } | ||
165 | WREG32(UVD_VCPU_CHIP_ID, chip_id); | ||
166 | |||
167 | return 0; | ||
168 | } | ||
169 | |||
71 | u32 rv770_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base) | 170 | u32 rv770_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base) |
72 | { | 171 | { |
73 | struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc_id]; | 172 | struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc_id]; |
@@ -1040,6 +1139,17 @@ static int rv770_startup(struct radeon_device *rdev) | |||
1040 | return r; | 1139 | return r; |
1041 | } | 1140 | } |
1042 | 1141 | ||
1142 | r = rv770_uvd_resume(rdev); | ||
1143 | if (!r) { | ||
1144 | r = radeon_fence_driver_start_ring(rdev, | ||
1145 | R600_RING_TYPE_UVD_INDEX); | ||
1146 | if (r) | ||
1147 | dev_err(rdev->dev, "UVD fences init error (%d).\n", r); | ||
1148 | } | ||
1149 | |||
1150 | if (r) | ||
1151 | rdev->ring[R600_RING_TYPE_UVD_INDEX].ring_size = 0; | ||
1152 | |||
1043 | /* Enable IRQ */ | 1153 | /* Enable IRQ */ |
1044 | r = r600_irq_init(rdev); | 1154 | r = r600_irq_init(rdev); |
1045 | if (r) { | 1155 | if (r) { |
@@ -1074,6 +1184,19 @@ static int rv770_startup(struct radeon_device *rdev) | |||
1074 | if (r) | 1184 | if (r) |
1075 | return r; | 1185 | return r; |
1076 | 1186 | ||
1187 | ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX]; | ||
1188 | if (ring->ring_size) { | ||
1189 | r = radeon_ring_init(rdev, ring, ring->ring_size, | ||
1190 | R600_WB_UVD_RPTR_OFFSET, | ||
1191 | UVD_RBC_RB_RPTR, UVD_RBC_RB_WPTR, | ||
1192 | 0, 0xfffff, RADEON_CP_PACKET2); | ||
1193 | if (!r) | ||
1194 | r = r600_uvd_init(rdev); | ||
1195 | |||
1196 | if (r) | ||
1197 | DRM_ERROR("radeon: failed initializing UVD (%d).\n", r); | ||
1198 | } | ||
1199 | |||
1077 | r = radeon_ib_pool_init(rdev); | 1200 | r = radeon_ib_pool_init(rdev); |
1078 | if (r) { | 1201 | if (r) { |
1079 | dev_err(rdev->dev, "IB initialization failed (%d).\n", r); | 1202 | dev_err(rdev->dev, "IB initialization failed (%d).\n", r); |
@@ -1115,6 +1238,7 @@ int rv770_resume(struct radeon_device *rdev) | |||
1115 | int rv770_suspend(struct radeon_device *rdev) | 1238 | int rv770_suspend(struct radeon_device *rdev) |
1116 | { | 1239 | { |
1117 | r600_audio_fini(rdev); | 1240 | r600_audio_fini(rdev); |
1241 | radeon_uvd_suspend(rdev); | ||
1118 | r700_cp_stop(rdev); | 1242 | r700_cp_stop(rdev); |
1119 | r600_dma_stop(rdev); | 1243 | r600_dma_stop(rdev); |
1120 | r600_irq_suspend(rdev); | 1244 | r600_irq_suspend(rdev); |
@@ -1190,6 +1314,13 @@ int rv770_init(struct radeon_device *rdev) | |||
1190 | rdev->ring[R600_RING_TYPE_DMA_INDEX].ring_obj = NULL; | 1314 | rdev->ring[R600_RING_TYPE_DMA_INDEX].ring_obj = NULL; |
1191 | r600_ring_init(rdev, &rdev->ring[R600_RING_TYPE_DMA_INDEX], 64 * 1024); | 1315 | r600_ring_init(rdev, &rdev->ring[R600_RING_TYPE_DMA_INDEX], 64 * 1024); |
1192 | 1316 | ||
1317 | r = radeon_uvd_init(rdev); | ||
1318 | if (!r) { | ||
1319 | rdev->ring[R600_RING_TYPE_UVD_INDEX].ring_obj = NULL; | ||
1320 | r600_ring_init(rdev, &rdev->ring[R600_RING_TYPE_UVD_INDEX], | ||
1321 | 4096); | ||
1322 | } | ||
1323 | |||
1193 | rdev->ih.ring_obj = NULL; | 1324 | rdev->ih.ring_obj = NULL; |
1194 | r600_ih_ring_init(rdev, 64 * 1024); | 1325 | r600_ih_ring_init(rdev, 64 * 1024); |
1195 | 1326 | ||
@@ -1224,6 +1355,7 @@ void rv770_fini(struct radeon_device *rdev) | |||
1224 | radeon_ib_pool_fini(rdev); | 1355 | radeon_ib_pool_fini(rdev); |
1225 | radeon_irq_kms_fini(rdev); | 1356 | radeon_irq_kms_fini(rdev); |
1226 | rv770_pcie_gart_fini(rdev); | 1357 | rv770_pcie_gart_fini(rdev); |
1358 | radeon_uvd_fini(rdev); | ||
1227 | r600_vram_scratch_fini(rdev); | 1359 | r600_vram_scratch_fini(rdev); |
1228 | radeon_gem_fini(rdev); | 1360 | radeon_gem_fini(rdev); |
1229 | radeon_fence_driver_fini(rdev); | 1361 | radeon_fence_driver_fini(rdev); |
diff --git a/drivers/gpu/drm/radeon/rv770d.h b/drivers/gpu/drm/radeon/rv770d.h index c55f950a4af7..da158b541720 100644 --- a/drivers/gpu/drm/radeon/rv770d.h +++ b/drivers/gpu/drm/radeon/rv770d.h | |||
@@ -671,4 +671,18 @@ | |||
671 | # define TARGET_LINK_SPEED_MASK (0xf << 0) | 671 | # define TARGET_LINK_SPEED_MASK (0xf << 0) |
672 | # define SELECTABLE_DEEMPHASIS (1 << 6) | 672 | # define SELECTABLE_DEEMPHASIS (1 << 6) |
673 | 673 | ||
674 | /* UVD */ | ||
675 | #define UVD_LMI_EXT40_ADDR 0xf498 | ||
676 | #define UVD_VCPU_CHIP_ID 0xf4d4 | ||
677 | #define UVD_VCPU_CACHE_OFFSET0 0xf4d8 | ||
678 | #define UVD_VCPU_CACHE_SIZE0 0xf4dc | ||
679 | #define UVD_VCPU_CACHE_OFFSET1 0xf4e0 | ||
680 | #define UVD_VCPU_CACHE_SIZE1 0xf4e4 | ||
681 | #define UVD_VCPU_CACHE_OFFSET2 0xf4e8 | ||
682 | #define UVD_VCPU_CACHE_SIZE2 0xf4ec | ||
683 | #define UVD_LMI_ADDR_EXT 0xf594 | ||
684 | |||
685 | #define UVD_RBC_RB_RPTR 0xf690 | ||
686 | #define UVD_RBC_RB_WPTR 0xf694 | ||
687 | |||
674 | #endif | 688 | #endif |
diff --git a/drivers/gpu/drm/radeon/si.c b/drivers/gpu/drm/radeon/si.c index ace45da91434..3e9782dc35bf 100644 --- a/drivers/gpu/drm/radeon/si.c +++ b/drivers/gpu/drm/radeon/si.c | |||
@@ -4333,6 +4333,16 @@ static int si_startup(struct radeon_device *rdev) | |||
4333 | return r; | 4333 | return r; |
4334 | } | 4334 | } |
4335 | 4335 | ||
4336 | r = rv770_uvd_resume(rdev); | ||
4337 | if (!r) { | ||
4338 | r = radeon_fence_driver_start_ring(rdev, | ||
4339 | R600_RING_TYPE_UVD_INDEX); | ||
4340 | if (r) | ||
4341 | dev_err(rdev->dev, "UVD fences init error (%d).\n", r); | ||
4342 | } | ||
4343 | if (r) | ||
4344 | rdev->ring[R600_RING_TYPE_UVD_INDEX].ring_size = 0; | ||
4345 | |||
4336 | /* Enable IRQ */ | 4346 | /* Enable IRQ */ |
4337 | r = si_irq_init(rdev); | 4347 | r = si_irq_init(rdev); |
4338 | if (r) { | 4348 | if (r) { |
@@ -4390,6 +4400,18 @@ static int si_startup(struct radeon_device *rdev) | |||
4390 | if (r) | 4400 | if (r) |
4391 | return r; | 4401 | return r; |
4392 | 4402 | ||
4403 | ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX]; | ||
4404 | if (ring->ring_size) { | ||
4405 | r = radeon_ring_init(rdev, ring, ring->ring_size, | ||
4406 | R600_WB_UVD_RPTR_OFFSET, | ||
4407 | UVD_RBC_RB_RPTR, UVD_RBC_RB_WPTR, | ||
4408 | 0, 0xfffff, RADEON_CP_PACKET2); | ||
4409 | if (!r) | ||
4410 | r = r600_uvd_init(rdev); | ||
4411 | if (r) | ||
4412 | DRM_ERROR("radeon: failed initializing UVD (%d).\n", r); | ||
4413 | } | ||
4414 | |||
4393 | r = radeon_ib_pool_init(rdev); | 4415 | r = radeon_ib_pool_init(rdev); |
4394 | if (r) { | 4416 | if (r) { |
4395 | dev_err(rdev->dev, "IB initialization failed (%d).\n", r); | 4417 | dev_err(rdev->dev, "IB initialization failed (%d).\n", r); |
@@ -4433,6 +4455,8 @@ int si_suspend(struct radeon_device *rdev) | |||
4433 | radeon_vm_manager_fini(rdev); | 4455 | radeon_vm_manager_fini(rdev); |
4434 | si_cp_enable(rdev, false); | 4456 | si_cp_enable(rdev, false); |
4435 | cayman_dma_stop(rdev); | 4457 | cayman_dma_stop(rdev); |
4458 | r600_uvd_rbc_stop(rdev); | ||
4459 | radeon_uvd_suspend(rdev); | ||
4436 | si_irq_suspend(rdev); | 4460 | si_irq_suspend(rdev); |
4437 | radeon_wb_disable(rdev); | 4461 | radeon_wb_disable(rdev); |
4438 | si_pcie_gart_disable(rdev); | 4462 | si_pcie_gart_disable(rdev); |
@@ -4518,6 +4542,13 @@ int si_init(struct radeon_device *rdev) | |||
4518 | ring->ring_obj = NULL; | 4542 | ring->ring_obj = NULL; |
4519 | r600_ring_init(rdev, ring, 64 * 1024); | 4543 | r600_ring_init(rdev, ring, 64 * 1024); |
4520 | 4544 | ||
4545 | r = radeon_uvd_init(rdev); | ||
4546 | if (!r) { | ||
4547 | ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX]; | ||
4548 | ring->ring_obj = NULL; | ||
4549 | r600_ring_init(rdev, ring, 4096); | ||
4550 | } | ||
4551 | |||
4521 | rdev->ih.ring_obj = NULL; | 4552 | rdev->ih.ring_obj = NULL; |
4522 | r600_ih_ring_init(rdev, 64 * 1024); | 4553 | r600_ih_ring_init(rdev, 64 * 1024); |
4523 | 4554 | ||
@@ -4566,6 +4597,7 @@ void si_fini(struct radeon_device *rdev) | |||
4566 | radeon_vm_manager_fini(rdev); | 4597 | radeon_vm_manager_fini(rdev); |
4567 | radeon_ib_pool_fini(rdev); | 4598 | radeon_ib_pool_fini(rdev); |
4568 | radeon_irq_kms_fini(rdev); | 4599 | radeon_irq_kms_fini(rdev); |
4600 | radeon_uvd_fini(rdev); | ||
4569 | si_pcie_gart_fini(rdev); | 4601 | si_pcie_gart_fini(rdev); |
4570 | r600_vram_scratch_fini(rdev); | 4602 | r600_vram_scratch_fini(rdev); |
4571 | radeon_gem_fini(rdev); | 4603 | radeon_gem_fini(rdev); |
diff --git a/drivers/gpu/drm/radeon/sid.h b/drivers/gpu/drm/radeon/sid.h index f84cff0aafcc..1fb8ee2c45dc 100644 --- a/drivers/gpu/drm/radeon/sid.h +++ b/drivers/gpu/drm/radeon/sid.h | |||
@@ -800,6 +800,12 @@ | |||
800 | # define THREAD_TRACE_FINISH (55 << 0) | 800 | # define THREAD_TRACE_FINISH (55 << 0) |
801 | 801 | ||
802 | /* | 802 | /* |
803 | * UVD | ||
804 | */ | ||
805 | #define UVD_RBC_RB_RPTR 0xF690 | ||
806 | #define UVD_RBC_RB_WPTR 0xF694 | ||
807 | |||
808 | /* | ||
803 | * PM4 | 809 | * PM4 |
804 | */ | 810 | */ |
805 | #define PACKET0(reg, n) ((RADEON_PACKET_TYPE0 << 30) | \ | 811 | #define PACKET0(reg, n) ((RADEON_PACKET_TYPE0 << 30) | \ |
diff --git a/include/uapi/drm/radeon_drm.h b/include/uapi/drm/radeon_drm.h index 6fd25563f301..b1c1a2a4fe33 100644 --- a/include/uapi/drm/radeon_drm.h +++ b/include/uapi/drm/radeon_drm.h | |||
@@ -918,6 +918,7 @@ struct drm_radeon_gem_va { | |||
918 | #define RADEON_CS_RING_GFX 0 | 918 | #define RADEON_CS_RING_GFX 0 |
919 | #define RADEON_CS_RING_COMPUTE 1 | 919 | #define RADEON_CS_RING_COMPUTE 1 |
920 | #define RADEON_CS_RING_DMA 2 | 920 | #define RADEON_CS_RING_DMA 2 |
921 | #define RADEON_CS_RING_UVD 3 | ||
921 | /* The third dword of RADEON_CHUNK_ID_FLAGS is a sint32 that sets the priority */ | 922 | /* The third dword of RADEON_CHUNK_ID_FLAGS is a sint32 that sets the priority */ |
922 | /* 0 = normal, + = higher priority, - = lower priority */ | 923 | /* 0 = normal, + = higher priority, - = lower priority */ |
923 | 924 | ||