1/* 2 * Copyright 2013 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 * Authors: Christian König <christian.koenig@amd.com> 26 */ 27 28#include <linux/firmware.h> 29#include <drm/drmP.h> 30#include "radeon.h" 31#include "radeon_asic.h" 32#include "sid.h" 33 34/** 35 * vce_v1_0_get_rptr - get read pointer 36 * 37 * @rdev: radeon_device pointer 38 * @ring: radeon_ring pointer 39 * 40 * Returns the current hardware read pointer 41 */ 42uint32_t vce_v1_0_get_rptr(struct radeon_device *rdev, 43 struct radeon_ring *ring) 44{ 45 if (ring->idx == TN_RING_TYPE_VCE1_INDEX) 46 return RREG32(VCE_RB_RPTR); 47 else 48 return RREG32(VCE_RB_RPTR2); 49} 50 51/** 52 * vce_v1_0_get_wptr - get write pointer 53 * 54 * @rdev: radeon_device pointer 55 * @ring: radeon_ring pointer 56 * 57 * Returns the current hardware write pointer 58 */ 59uint32_t vce_v1_0_get_wptr(struct radeon_device *rdev, 60 struct radeon_ring *ring) 61{ 62 if (ring->idx == TN_RING_TYPE_VCE1_INDEX) 63 return RREG32(VCE_RB_WPTR); 64 else 65 return RREG32(VCE_RB_WPTR2); 66} 67 68/** 69 * vce_v1_0_set_wptr - set write pointer 70 * 71 * @rdev: radeon_device pointer 72 * @ring: radeon_ring pointer 73 * 74 * Commits the write pointer to the hardware 75 */ 76void vce_v1_0_set_wptr(struct radeon_device *rdev, 77 struct radeon_ring *ring) 78{ 79 if (ring->idx == TN_RING_TYPE_VCE1_INDEX) 80 WREG32(VCE_RB_WPTR, ring->wptr); 81 else 82 WREG32(VCE_RB_WPTR2, ring->wptr); 83} 84 85/** 86 * vce_v1_0_start - start VCE block 87 * 88 * @rdev: radeon_device pointer 89 * 90 * Setup and start the VCE block 91 */ 92int vce_v1_0_start(struct radeon_device *rdev) 93{ 94 struct radeon_ring *ring; 95 int i, j, r; 96 97 /* set BUSY flag */ 98 WREG32_P(VCE_STATUS, 1, ~1); 99 100 ring = &rdev->ring[TN_RING_TYPE_VCE1_INDEX]; 101 WREG32(VCE_RB_RPTR, ring->wptr); 102 WREG32(VCE_RB_WPTR, ring->wptr); 103 WREG32(VCE_RB_BASE_LO, ring->gpu_addr); 104 WREG32(VCE_RB_BASE_HI, upper_32_bits(ring->gpu_addr)); 105 WREG32(VCE_RB_SIZE, ring->ring_size / 4); 106 107 ring = &rdev->ring[TN_RING_TYPE_VCE2_INDEX]; 108 WREG32(VCE_RB_RPTR2, ring->wptr); 109 WREG32(VCE_RB_WPTR2, ring->wptr); 110 WREG32(VCE_RB_BASE_LO2, ring->gpu_addr); 111 WREG32(VCE_RB_BASE_HI2, upper_32_bits(ring->gpu_addr)); 112 WREG32(VCE_RB_SIZE2, ring->ring_size / 4); 113 114 WREG32_P(VCE_VCPU_CNTL, VCE_CLK_EN, ~VCE_CLK_EN); 115 116 WREG32_P(VCE_SOFT_RESET, 117 VCE_ECPU_SOFT_RESET | 118 VCE_FME_SOFT_RESET, ~( 119 VCE_ECPU_SOFT_RESET | 120 VCE_FME_SOFT_RESET)); 121 122 mdelay(100); 123 124 WREG32_P(VCE_SOFT_RESET, 0, ~( 125 VCE_ECPU_SOFT_RESET | 126 VCE_FME_SOFT_RESET)); 127 128 for (i = 0; i < 10; ++i) { 129 uint32_t status; 130 for (j = 0; j < 100; ++j) { 131 status = RREG32(VCE_STATUS); 132 if (status & 2) 133 break; 134 mdelay(10); 135 } 136 r = 0; 137 if (status & 2) 138 break; 139 140 DRM_ERROR("VCE not responding, trying to reset the ECPU!!!\n"); 141 WREG32_P(VCE_SOFT_RESET, VCE_ECPU_SOFT_RESET, ~VCE_ECPU_SOFT_RESET); 142 mdelay(10); 143 WREG32_P(VCE_SOFT_RESET, 0, ~VCE_ECPU_SOFT_RESET); 144 mdelay(10); 145 r = -1; 146 } 147 148 /* clear BUSY flag */ 149 WREG32_P(VCE_STATUS, 0, ~1); 150 151 if (r) { 152 DRM_ERROR("VCE not responding, giving up!!!\n"); 153 return r; 154 } 155 156 return 0; 157} 158 159int vce_v1_0_init(struct radeon_device *rdev) 160{ 161 struct radeon_ring *ring; 162 int r; 163 164 r = vce_v1_0_start(rdev); 165 if (r) 166 return r; 167 168 ring = &rdev->ring[TN_RING_TYPE_VCE1_INDEX]; 169 ring->ready = true; 170 r = radeon_ring_test(rdev, TN_RING_TYPE_VCE1_INDEX, ring); 171 if (r) { 172 ring->ready = false; 173 return r; 174 } 175 176 ring = &rdev->ring[TN_RING_TYPE_VCE2_INDEX]; 177 ring->ready = true; 178 r = radeon_ring_test(rdev, TN_RING_TYPE_VCE2_INDEX, ring); 179 if (r) { 180 ring->ready = false; 181 return r; 182 } 183 184 DRM_INFO("VCE initialized successfully.\n"); 185 186 return 0; 187} 188