1/* $NetBSD: amdgpu_jpeg.c,v 1.2 2021/12/18 23:44:58 riastradh Exp $ */ 2 3/* 4 * Copyright 2019 Advanced Micro Devices, Inc. 5 * All Rights Reserved. 6 * 7 * Permission is hereby granted, free of charge, to any person obtaining a 8 * copy of this software and associated documentation files (the 9 * "Software"), to deal in the Software without restriction, including 10 * without limitation the rights to use, copy, modify, merge, publish, 11 * distribute, sub license, and/or sell copies of the Software, and to 12 * permit persons to whom the Software is furnished to do so, subject to 13 * the following conditions: 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 18 * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, 19 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 20 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 21 * USE OR OTHER DEALINGS IN THE SOFTWARE. 22 * 23 * The above copyright notice and this permission notice (including the 24 * next paragraph) shall be included in all copies or substantial portions 25 * of the Software. 26 * 27 */ 28 29#include <sys/cdefs.h> 30__KERNEL_RCSID(0, "$NetBSD: amdgpu_jpeg.c,v 1.2 2021/12/18 23:44:58 riastradh Exp $"); 31 32#include "amdgpu.h" 33#include "amdgpu_jpeg.h" 34#include "amdgpu_pm.h" 35#include "soc15d.h" 36#include "soc15_common.h" 37 38#define JPEG_IDLE_TIMEOUT msecs_to_jiffies(1000) 39 40static void amdgpu_jpeg_idle_work_handler(struct work_struct *work); 41 42int amdgpu_jpeg_sw_init(struct amdgpu_device *adev) 43{ 44 INIT_DELAYED_WORK(&adev->jpeg.idle_work, amdgpu_jpeg_idle_work_handler); 45 46 return 0; 47} 48 49int amdgpu_jpeg_sw_fini(struct amdgpu_device *adev) 50{ 51 int i; 52 53 cancel_delayed_work_sync(&adev->jpeg.idle_work); 54 55 for (i = 0; i < adev->jpeg.num_jpeg_inst; ++i) { 56 if (adev->jpeg.harvest_config & (1 << i)) 57 continue; 58 59 amdgpu_ring_fini(&adev->jpeg.inst[i].ring_dec); 60 } 61 62 return 0; 63} 64 65int amdgpu_jpeg_suspend(struct amdgpu_device *adev) 66{ 67 cancel_delayed_work_sync(&adev->jpeg.idle_work); 68 69 return 0; 70} 71 72int amdgpu_jpeg_resume(struct amdgpu_device *adev) 73{ 74 return 0; 75} 76 77static void amdgpu_jpeg_idle_work_handler(struct work_struct *work) 78{ 79 struct amdgpu_device *adev = 80 container_of(work, struct amdgpu_device, jpeg.idle_work.work); 81 unsigned int fences = 0; 82 unsigned int i; 83 84 for (i = 0; i < adev->jpeg.num_jpeg_inst; ++i) { 85 if (adev->jpeg.harvest_config & (1 << i)) 86 continue; 87 88 fences += amdgpu_fence_count_emitted(&adev->jpeg.inst[i].ring_dec); 89 } 90 91 if (fences == 0) 92 amdgpu_device_ip_set_powergating_state(adev, AMD_IP_BLOCK_TYPE_JPEG, 93 AMD_PG_STATE_GATE); 94 else 95 schedule_delayed_work(&adev->jpeg.idle_work, JPEG_IDLE_TIMEOUT); 96} 97 98void amdgpu_jpeg_ring_begin_use(struct amdgpu_ring *ring) 99{ 100 struct amdgpu_device *adev = ring->adev; 101 bool set_clocks = !cancel_delayed_work_sync(&adev->jpeg.idle_work); 102 103 if (set_clocks) 104 amdgpu_device_ip_set_powergating_state(adev, AMD_IP_BLOCK_TYPE_JPEG, 105 AMD_PG_STATE_UNGATE); 106} 107 108void amdgpu_jpeg_ring_end_use(struct amdgpu_ring *ring) 109{ 110 schedule_delayed_work(&ring->adev->jpeg.idle_work, JPEG_IDLE_TIMEOUT); 111} 112 113int amdgpu_jpeg_dec_ring_test_ring(struct amdgpu_ring *ring) 114{ 115 struct amdgpu_device *adev = ring->adev; 116 uint32_t tmp = 0; 117 unsigned i; 118 int r; 119 120 WREG32(adev->jpeg.inst[ring->me].external.jpeg_pitch, 0xCAFEDEAD); 121 r = amdgpu_ring_alloc(ring, 3); 122 if (r) 123 return r; 124 125 amdgpu_ring_write(ring, PACKET0(adev->jpeg.internal.jpeg_pitch, 0)); 126 amdgpu_ring_write(ring, 0xDEADBEEF); 127 amdgpu_ring_commit(ring); 128 129 for (i = 0; i < adev->usec_timeout; i++) { 130 tmp = RREG32(adev->jpeg.inst[ring->me].external.jpeg_pitch); 131 if (tmp == 0xDEADBEEF) 132 break; 133 udelay(1); 134 } 135 136 if (i >= adev->usec_timeout) 137 r = -ETIMEDOUT; 138 139 return r; 140} 141 142static int amdgpu_jpeg_dec_set_reg(struct amdgpu_ring *ring, uint32_t handle, 143 struct dma_fence **fence) 144{ 145 struct amdgpu_device *adev = ring->adev; 146 struct amdgpu_job *job; 147 struct amdgpu_ib *ib; 148 struct dma_fence *f = NULL; 149 const unsigned ib_size_dw = 16; 150 int i, r; 151 152 r = amdgpu_job_alloc_with_ib(ring->adev, ib_size_dw * 4, &job); 153 if (r) 154 return r; 155 156 ib = &job->ibs[0]; 157 158 ib->ptr[0] = PACKETJ(adev->jpeg.internal.jpeg_pitch, 0, 0, PACKETJ_TYPE0); 159 ib->ptr[1] = 0xDEADBEEF; 160 for (i = 2; i < 16; i += 2) { 161 ib->ptr[i] = PACKETJ(0, 0, 0, PACKETJ_TYPE6); 162 ib->ptr[i+1] = 0; 163 } 164 ib->length_dw = 16; 165 166 r = amdgpu_job_submit_direct(job, ring, &f); 167 if (r) 168 goto err; 169 170 if (fence) 171 *fence = dma_fence_get(f); 172 dma_fence_put(f); 173 174 return 0; 175 176err: 177 amdgpu_job_free(job); 178 return r; 179} 180 181int amdgpu_jpeg_dec_ring_test_ib(struct amdgpu_ring *ring, long timeout) 182{ 183 struct amdgpu_device *adev = ring->adev; 184 uint32_t tmp = 0; 185 unsigned i; 186 struct dma_fence *fence = NULL; 187 long r = 0; 188 189 r = amdgpu_jpeg_dec_set_reg(ring, 1, &fence); 190 if (r) 191 goto error; 192 193 r = dma_fence_wait_timeout(fence, false, timeout); 194 if (r == 0) { 195 r = -ETIMEDOUT; 196 goto error; 197 } else if (r < 0) { 198 goto error; 199 } else { 200 r = 0; 201 } 202 203 for (i = 0; i < adev->usec_timeout; i++) { 204 tmp = RREG32(adev->jpeg.inst[ring->me].external.jpeg_pitch); 205 if (tmp == 0xDEADBEEF) 206 break; 207 udelay(1); 208 } 209 210 if (i >= adev->usec_timeout) 211 r = -ETIMEDOUT; 212 213 dma_fence_put(fence); 214error: 215 return r; 216} 217