linux/drivers/gpu/drm/amd/amdgpu/amdgpu_jpeg.c
<<
>>
Prefs
   1/*
   2 * Copyright 2019 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#include "amdgpu.h"
  28#include "amdgpu_jpeg.h"
  29#include "amdgpu_pm.h"
  30#include "soc15d.h"
  31#include "soc15_common.h"
  32
  33#define JPEG_IDLE_TIMEOUT       msecs_to_jiffies(1000)
  34
  35static void amdgpu_jpeg_idle_work_handler(struct work_struct *work);
  36
  37int amdgpu_jpeg_sw_init(struct amdgpu_device *adev)
  38{
  39        INIT_DELAYED_WORK(&adev->jpeg.idle_work, amdgpu_jpeg_idle_work_handler);
  40        mutex_init(&adev->jpeg.jpeg_pg_lock);
  41        atomic_set(&adev->jpeg.total_submission_cnt, 0);
  42
  43        return 0;
  44}
  45
  46int amdgpu_jpeg_sw_fini(struct amdgpu_device *adev)
  47{
  48        int i;
  49
  50        for (i = 0; i < adev->jpeg.num_jpeg_inst; ++i) {
  51                if (adev->jpeg.harvest_config & (1 << i))
  52                        continue;
  53
  54                amdgpu_ring_fini(&adev->jpeg.inst[i].ring_dec);
  55        }
  56
  57        mutex_destroy(&adev->jpeg.jpeg_pg_lock);
  58
  59        return 0;
  60}
  61
  62int amdgpu_jpeg_suspend(struct amdgpu_device *adev)
  63{
  64        cancel_delayed_work_sync(&adev->jpeg.idle_work);
  65
  66        return 0;
  67}
  68
  69int amdgpu_jpeg_resume(struct amdgpu_device *adev)
  70{
  71        return 0;
  72}
  73
  74static void amdgpu_jpeg_idle_work_handler(struct work_struct *work)
  75{
  76        struct amdgpu_device *adev =
  77                container_of(work, struct amdgpu_device, jpeg.idle_work.work);
  78        unsigned int fences = 0;
  79        unsigned int i;
  80
  81        for (i = 0; i < adev->jpeg.num_jpeg_inst; ++i) {
  82                if (adev->jpeg.harvest_config & (1 << i))
  83                        continue;
  84
  85                fences += amdgpu_fence_count_emitted(&adev->jpeg.inst[i].ring_dec);
  86        }
  87
  88        if (!fences && !atomic_read(&adev->jpeg.total_submission_cnt))
  89                amdgpu_device_ip_set_powergating_state(adev, AMD_IP_BLOCK_TYPE_JPEG,
  90                                                       AMD_PG_STATE_GATE);
  91        else
  92                schedule_delayed_work(&adev->jpeg.idle_work, JPEG_IDLE_TIMEOUT);
  93}
  94
  95void amdgpu_jpeg_ring_begin_use(struct amdgpu_ring *ring)
  96{
  97        struct amdgpu_device *adev = ring->adev;
  98
  99        atomic_inc(&adev->jpeg.total_submission_cnt);
 100        cancel_delayed_work_sync(&adev->jpeg.idle_work);
 101
 102        mutex_lock(&adev->jpeg.jpeg_pg_lock);
 103        amdgpu_device_ip_set_powergating_state(adev, AMD_IP_BLOCK_TYPE_JPEG,
 104                                                       AMD_PG_STATE_UNGATE);
 105        mutex_unlock(&adev->jpeg.jpeg_pg_lock);
 106}
 107
 108void amdgpu_jpeg_ring_end_use(struct amdgpu_ring *ring)
 109{
 110        atomic_dec(&ring->adev->jpeg.total_submission_cnt);
 111        schedule_delayed_work(&ring->adev->jpeg.idle_work, JPEG_IDLE_TIMEOUT);
 112}
 113
 114int amdgpu_jpeg_dec_ring_test_ring(struct amdgpu_ring *ring)
 115{
 116        struct amdgpu_device *adev = ring->adev;
 117        uint32_t tmp = 0;
 118        unsigned i;
 119        int r;
 120
 121        WREG32(adev->jpeg.inst[ring->me].external.jpeg_pitch, 0xCAFEDEAD);
 122        r = amdgpu_ring_alloc(ring, 3);
 123        if (r)
 124                return r;
 125
 126        amdgpu_ring_write(ring, PACKET0(adev->jpeg.internal.jpeg_pitch, 0));
 127        amdgpu_ring_write(ring, 0xDEADBEEF);
 128        amdgpu_ring_commit(ring);
 129
 130        for (i = 0; i < adev->usec_timeout; i++) {
 131                tmp = RREG32(adev->jpeg.inst[ring->me].external.jpeg_pitch);
 132                if (tmp == 0xDEADBEEF)
 133                        break;
 134                udelay(1);
 135        }
 136
 137        if (i >= adev->usec_timeout)
 138                r = -ETIMEDOUT;
 139
 140        return r;
 141}
 142
 143static int amdgpu_jpeg_dec_set_reg(struct amdgpu_ring *ring, uint32_t handle,
 144                struct dma_fence **fence)
 145{
 146        struct amdgpu_device *adev = ring->adev;
 147        struct amdgpu_job *job;
 148        struct amdgpu_ib *ib;
 149        struct dma_fence *f = NULL;
 150        const unsigned ib_size_dw = 16;
 151        int i, r;
 152
 153        r = amdgpu_job_alloc_with_ib(ring->adev, ib_size_dw * 4,
 154                                        AMDGPU_IB_POOL_DIRECT, &job);
 155        if (r)
 156                return r;
 157
 158        ib = &job->ibs[0];
 159
 160        ib->ptr[0] = PACKETJ(adev->jpeg.internal.jpeg_pitch, 0, 0, PACKETJ_TYPE0);
 161        ib->ptr[1] = 0xDEADBEEF;
 162        for (i = 2; i < 16; i += 2) {
 163                ib->ptr[i] = PACKETJ(0, 0, 0, PACKETJ_TYPE6);
 164                ib->ptr[i+1] = 0;
 165        }
 166        ib->length_dw = 16;
 167
 168        r = amdgpu_job_submit_direct(job, ring, &f);
 169        if (r)
 170                goto err;
 171
 172        if (fence)
 173                *fence = dma_fence_get(f);
 174        dma_fence_put(f);
 175
 176        return 0;
 177
 178err:
 179        amdgpu_job_free(job);
 180        return r;
 181}
 182
 183int amdgpu_jpeg_dec_ring_test_ib(struct amdgpu_ring *ring, long timeout)
 184{
 185        struct amdgpu_device *adev = ring->adev;
 186        uint32_t tmp = 0;
 187        unsigned i;
 188        struct dma_fence *fence = NULL;
 189        long r = 0;
 190
 191        r = amdgpu_jpeg_dec_set_reg(ring, 1, &fence);
 192        if (r)
 193                goto error;
 194
 195        r = dma_fence_wait_timeout(fence, false, timeout);
 196        if (r == 0) {
 197                r = -ETIMEDOUT;
 198                goto error;
 199        } else if (r < 0) {
 200                goto error;
 201        } else {
 202                r = 0;
 203        }
 204
 205        for (i = 0; i < adev->usec_timeout; i++) {
 206                tmp = RREG32(adev->jpeg.inst[ring->me].external.jpeg_pitch);
 207                if (tmp == 0xDEADBEEF)
 208                        break;
 209                udelay(1);
 210        }
 211
 212        if (i >= adev->usec_timeout)
 213                r = -ETIMEDOUT;
 214
 215        dma_fence_put(fence);
 216error:
 217        return r;
 218}
 219