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 30 #include "radeon.h" 31 #include "radeon_asic.h" 32 #include "cikd.h" 33 #include "vce.h" 34 35 #define VCE_V2_0_FW_SIZE (256 * 1024) 36 #define VCE_V2_0_STACK_SIZE (64 * 1024) 37 #define VCE_V2_0_DATA_SIZE (23552 * RADEON_MAX_VCE_HANDLES) 38 39 static void vce_v2_0_set_sw_cg(struct radeon_device *rdev, bool gated) 40 { 41 u32 tmp; 42 43 if (gated) { 44 tmp = RREG32(VCE_CLOCK_GATING_B); 45 tmp |= 0xe70000; 46 WREG32(VCE_CLOCK_GATING_B, tmp); 47 48 tmp = RREG32(VCE_UENC_CLOCK_GATING); 49 tmp |= 0xff000000; 50 WREG32(VCE_UENC_CLOCK_GATING, tmp); 51 52 tmp = RREG32(VCE_UENC_REG_CLOCK_GATING); 53 tmp &= ~0x3fc; 54 WREG32(VCE_UENC_REG_CLOCK_GATING, tmp); 55 56 WREG32(VCE_CGTT_CLK_OVERRIDE, 0); 57 } else { 58 tmp = RREG32(VCE_CLOCK_GATING_B); 59 tmp |= 0xe7; 60 tmp &= ~0xe70000; 61 WREG32(VCE_CLOCK_GATING_B, tmp); 62 63 tmp = RREG32(VCE_UENC_CLOCK_GATING); 64 tmp |= 0x1fe000; 65 tmp &= ~0xff000000; 66 WREG32(VCE_UENC_CLOCK_GATING, tmp); 67 68 tmp = RREG32(VCE_UENC_REG_CLOCK_GATING); 69 tmp |= 0x3fc; 70 WREG32(VCE_UENC_REG_CLOCK_GATING, tmp); 71 } 72 } 73 74 static void vce_v2_0_set_dyn_cg(struct radeon_device *rdev, bool gated) 75 { 76 u32 orig, tmp; 77 78 tmp = RREG32(VCE_CLOCK_GATING_B); 79 tmp &= ~0x00060006; 80 if (gated) { 81 tmp |= 0xe10000; 82 } else { 83 tmp |= 0xe1; 84 tmp &= ~0xe10000; 85 } 86 WREG32(VCE_CLOCK_GATING_B, tmp); 87 88 orig = tmp = RREG32(VCE_UENC_CLOCK_GATING); 89 tmp &= ~0x1fe000; 90 tmp &= ~0xff000000; 91 if (tmp != orig) 92 WREG32(VCE_UENC_CLOCK_GATING, tmp); 93 94 orig = tmp = RREG32(VCE_UENC_REG_CLOCK_GATING); 95 tmp &= ~0x3fc; 96 if (tmp != orig) 97 WREG32(VCE_UENC_REG_CLOCK_GATING, tmp); 98 99 if (gated) 100 WREG32(VCE_CGTT_CLK_OVERRIDE, 0); 101 } 102 103 static void vce_v2_0_disable_cg(struct radeon_device *rdev) 104 { 105 WREG32(VCE_CGTT_CLK_OVERRIDE, 7); 106 } 107 108 /* 109 * Local variable sw_cg is used for debugging purposes, in case we 110 * ran into problems with dynamic clock gating. Don't remove it. 111 */ 112 void vce_v2_0_enable_mgcg(struct radeon_device *rdev, bool enable) 113 { 114 bool sw_cg = false; 115 116 if (enable && (rdev->cg_flags & RADEON_CG_SUPPORT_VCE_MGCG)) { 117 if (sw_cg) 118 vce_v2_0_set_sw_cg(rdev, true); 119 else 120 vce_v2_0_set_dyn_cg(rdev, true); 121 } else { 122 vce_v2_0_disable_cg(rdev); 123 124 if (sw_cg) 125 vce_v2_0_set_sw_cg(rdev, false); 126 else 127 vce_v2_0_set_dyn_cg(rdev, false); 128 } 129 } 130 131 static void vce_v2_0_init_cg(struct radeon_device *rdev) 132 { 133 u32 tmp; 134 135 tmp = RREG32(VCE_CLOCK_GATING_A); 136 tmp &= ~(CGC_CLK_GATE_DLY_TIMER_MASK | CGC_CLK_GATER_OFF_DLY_TIMER_MASK); 137 tmp |= (CGC_CLK_GATE_DLY_TIMER(0) | CGC_CLK_GATER_OFF_DLY_TIMER(4)); 138 tmp |= CGC_UENC_WAIT_AWAKE; 139 WREG32(VCE_CLOCK_GATING_A, tmp); 140 141 tmp = RREG32(VCE_UENC_CLOCK_GATING); 142 tmp &= ~(CLOCK_ON_DELAY_MASK | CLOCK_OFF_DELAY_MASK); 143 tmp |= (CLOCK_ON_DELAY(0) | CLOCK_OFF_DELAY(4)); 144 WREG32(VCE_UENC_CLOCK_GATING, tmp); 145 146 tmp = RREG32(VCE_CLOCK_GATING_B); 147 tmp |= 0x10; 148 tmp &= ~0x100000; 149 WREG32(VCE_CLOCK_GATING_B, tmp); 150 } 151 152 unsigned vce_v2_0_bo_size(struct radeon_device *rdev) 153 { 154 WARN_ON(rdev->vce_fw->size > VCE_V2_0_FW_SIZE); 155 return VCE_V2_0_FW_SIZE + VCE_V2_0_STACK_SIZE + VCE_V2_0_DATA_SIZE; 156 } 157 158 int vce_v2_0_resume(struct radeon_device *rdev) 159 { 160 uint64_t addr = rdev->vce.gpu_addr; 161 uint32_t size; 162 163 WREG32_P(VCE_CLOCK_GATING_A, 0, ~(1 << 16)); 164 WREG32_P(VCE_UENC_CLOCK_GATING, 0x1FF000, ~0xFF9FF000); 165 WREG32_P(VCE_UENC_REG_CLOCK_GATING, 0x3F, ~0x3F); 166 WREG32(VCE_CLOCK_GATING_B, 0xf7); 167 168 WREG32(VCE_LMI_CTRL, 0x00398000); 169 WREG32_P(VCE_LMI_CACHE_CTRL, 0x0, ~0x1); 170 WREG32(VCE_LMI_SWAP_CNTL, 0); 171 WREG32(VCE_LMI_SWAP_CNTL1, 0); 172 WREG32(VCE_LMI_VM_CTRL, 0); 173 174 WREG32(VCE_LMI_VCPU_CACHE_40BIT_BAR, addr >> 8); 175 176 addr &= 0xff; 177 size = VCE_V2_0_FW_SIZE; 178 WREG32(VCE_VCPU_CACHE_OFFSET0, addr & 0x7fffffff); 179 WREG32(VCE_VCPU_CACHE_SIZE0, size); 180 181 addr += size; 182 size = VCE_V2_0_STACK_SIZE; 183 WREG32(VCE_VCPU_CACHE_OFFSET1, addr & 0x7fffffff); 184 WREG32(VCE_VCPU_CACHE_SIZE1, size); 185 186 addr += size; 187 size = VCE_V2_0_DATA_SIZE; 188 WREG32(VCE_VCPU_CACHE_OFFSET2, addr & 0x7fffffff); 189 WREG32(VCE_VCPU_CACHE_SIZE2, size); 190 191 WREG32_P(VCE_LMI_CTRL2, 0x0, ~0x100); 192 193 WREG32_P(VCE_SYS_INT_EN, VCE_SYS_INT_TRAP_INTERRUPT_EN, 194 ~VCE_SYS_INT_TRAP_INTERRUPT_EN); 195 196 vce_v2_0_init_cg(rdev); 197 198 return 0; 199 } 200