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 /drivers/gpu/drm/radeon/r600.c | |
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>
Diffstat (limited to 'drivers/gpu/drm/radeon/r600.c')
-rw-r--r-- | drivers/gpu/drm/radeon/r600.c | 291 |
1 files changed, 291 insertions, 0 deletions
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 | * |