linux/drivers/gpu/drm/radeon/uvd_v1_0.c
<<
>>
Prefs
   1/*
   2 * Copyright 2013 Advanced Micro Devices, Inc.
   3 *
   4 * Permission is hereby granted, free of charge, to any person obtaining a
   5 * copy of this software and associated documentation files (the "Software"),
   6 * to deal in the Software without restriction, including without limitation
   7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
   8 * and/or sell copies of the Software, and to permit persons to whom the
   9 * Software is furnished to do so, subject to the following conditions:
  10 *
  11 * The above copyright notice and this permission notice shall be included in
  12 * all copies or substantial portions of the Software.
  13 *
  14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
  18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  20 * OTHER DEALINGS IN THE SOFTWARE.
  21 *
  22 * Authors: Christian König <christian.koenig@amd.com>
  23 */
  24
  25#include <drm/drmP.h>
  26#include "radeon.h"
  27#include "radeon_asic.h"
  28#include "r600d.h"
  29
  30/**
  31 * uvd_v1_0_get_rptr - get read pointer
  32 *
  33 * @rdev: radeon_device pointer
  34 * @ring: radeon_ring pointer
  35 *
  36 * Returns the current hardware read pointer
  37 */
  38uint32_t uvd_v1_0_get_rptr(struct radeon_device *rdev,
  39                           struct radeon_ring *ring)
  40{
  41        return RREG32(UVD_RBC_RB_RPTR);
  42}
  43
  44/**
  45 * uvd_v1_0_get_wptr - get write pointer
  46 *
  47 * @rdev: radeon_device pointer
  48 * @ring: radeon_ring pointer
  49 *
  50 * Returns the current hardware write pointer
  51 */
  52uint32_t uvd_v1_0_get_wptr(struct radeon_device *rdev,
  53                           struct radeon_ring *ring)
  54{
  55        return RREG32(UVD_RBC_RB_WPTR);
  56}
  57
  58/**
  59 * uvd_v1_0_set_wptr - set write pointer
  60 *
  61 * @rdev: radeon_device pointer
  62 * @ring: radeon_ring pointer
  63 *
  64 * Commits the write pointer to the hardware
  65 */
  66void uvd_v1_0_set_wptr(struct radeon_device *rdev,
  67                       struct radeon_ring *ring)
  68{
  69        WREG32(UVD_RBC_RB_WPTR, ring->wptr);
  70}
  71
  72/**
  73 * uvd_v1_0_init - start and test UVD block
  74 *
  75 * @rdev: radeon_device pointer
  76 *
  77 * Initialize the hardware, boot up the VCPU and do some testing
  78 */
  79int uvd_v1_0_init(struct radeon_device *rdev)
  80{
  81        struct radeon_ring *ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX];
  82        uint32_t tmp;
  83        int r;
  84
  85        /* raise clocks while booting up the VCPU */
  86        radeon_set_uvd_clocks(rdev, 53300, 40000);
  87
  88        r = uvd_v1_0_start(rdev);
  89        if (r)
  90                goto done;
  91
  92        ring->ready = true;
  93        r = radeon_ring_test(rdev, R600_RING_TYPE_UVD_INDEX, ring);
  94        if (r) {
  95                ring->ready = false;
  96                goto done;
  97        }
  98
  99        r = radeon_ring_lock(rdev, ring, 10);
 100        if (r) {
 101                DRM_ERROR("radeon: ring failed to lock UVD ring (%d).\n", r);
 102                goto done;
 103        }
 104
 105        tmp = PACKET0(UVD_SEMA_WAIT_FAULT_TIMEOUT_CNTL, 0);
 106        radeon_ring_write(ring, tmp);
 107        radeon_ring_write(ring, 0xFFFFF);
 108
 109        tmp = PACKET0(UVD_SEMA_WAIT_INCOMPLETE_TIMEOUT_CNTL, 0);
 110        radeon_ring_write(ring, tmp);
 111        radeon_ring_write(ring, 0xFFFFF);
 112
 113        tmp = PACKET0(UVD_SEMA_SIGNAL_INCOMPLETE_TIMEOUT_CNTL, 0);
 114        radeon_ring_write(ring, tmp);
 115        radeon_ring_write(ring, 0xFFFFF);
 116
 117        /* Clear timeout status bits */
 118        radeon_ring_write(ring, PACKET0(UVD_SEMA_TIMEOUT_STATUS, 0));
 119        radeon_ring_write(ring, 0x8);
 120
 121        radeon_ring_write(ring, PACKET0(UVD_SEMA_CNTL, 0));
 122        radeon_ring_write(ring, 3);
 123
 124        radeon_ring_unlock_commit(rdev, ring);
 125
 126done:
 127        /* lower clocks again */
 128        radeon_set_uvd_clocks(rdev, 0, 0);
 129
 130        if (!r)
 131                DRM_INFO("UVD initialized successfully.\n");
 132
 133        return r;
 134}
 135
 136/**
 137 * uvd_v1_0_fini - stop the hardware block
 138 *
 139 * @rdev: radeon_device pointer
 140 *
 141 * Stop the UVD block, mark ring as not ready any more
 142 */
 143void uvd_v1_0_fini(struct radeon_device *rdev)
 144{
 145        struct radeon_ring *ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX];
 146
 147        uvd_v1_0_stop(rdev);
 148        ring->ready = false;
 149}
 150
 151/**
 152 * uvd_v1_0_start - start UVD block
 153 *
 154 * @rdev: radeon_device pointer
 155 *
 156 * Setup and start the UVD block
 157 */
 158int uvd_v1_0_start(struct radeon_device *rdev)
 159{
 160        struct radeon_ring *ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX];
 161        uint32_t rb_bufsz;
 162        int i, j, r;
 163
 164        /* disable byte swapping */
 165        u32 lmi_swap_cntl = 0;
 166        u32 mp_swap_cntl = 0;
 167
 168        /* disable clock gating */
 169        WREG32(UVD_CGC_GATE, 0);
 170
 171        /* disable interupt */
 172        WREG32_P(UVD_MASTINT_EN, 0, ~(1 << 1));
 173
 174        /* Stall UMC and register bus before resetting VCPU */
 175        WREG32_P(UVD_LMI_CTRL2, 1 << 8, ~(1 << 8));
 176        WREG32_P(UVD_RB_ARB_CTRL, 1 << 3, ~(1 << 3));
 177        mdelay(1);
 178
 179        /* put LMI, VCPU, RBC etc... into reset */
 180        WREG32(UVD_SOFT_RESET, LMI_SOFT_RESET | VCPU_SOFT_RESET |
 181               LBSI_SOFT_RESET | RBC_SOFT_RESET | CSM_SOFT_RESET |
 182               CXW_SOFT_RESET | TAP_SOFT_RESET | LMI_UMC_SOFT_RESET);
 183        mdelay(5);
 184
 185        /* take UVD block out of reset */
 186        WREG32_P(SRBM_SOFT_RESET, 0, ~SOFT_RESET_UVD);
 187        mdelay(5);
 188
 189        /* initialize UVD memory controller */
 190        WREG32(UVD_LMI_CTRL, 0x40 | (1 << 8) | (1 << 13) |
 191                             (1 << 21) | (1 << 9) | (1 << 20));
 192
 193#ifdef __BIG_ENDIAN
 194        /* swap (8 in 32) RB and IB */
 195        lmi_swap_cntl = 0xa;
 196        mp_swap_cntl = 0;
 197#endif
 198        WREG32(UVD_LMI_SWAP_CNTL, lmi_swap_cntl);
 199        WREG32(UVD_MP_SWAP_CNTL, mp_swap_cntl);
 200
 201        WREG32(UVD_MPC_SET_MUXA0, 0x40c2040);
 202        WREG32(UVD_MPC_SET_MUXA1, 0x0);
 203        WREG32(UVD_MPC_SET_MUXB0, 0x40c2040);
 204        WREG32(UVD_MPC_SET_MUXB1, 0x0);
 205        WREG32(UVD_MPC_SET_ALU, 0);
 206        WREG32(UVD_MPC_SET_MUX, 0x88);
 207
 208        /* take all subblocks out of reset, except VCPU */
 209        WREG32(UVD_SOFT_RESET, VCPU_SOFT_RESET);
 210        mdelay(5);
 211
 212        /* enable VCPU clock */
 213        WREG32(UVD_VCPU_CNTL,  1 << 9);
 214
 215        /* enable UMC */
 216        WREG32_P(UVD_LMI_CTRL2, 0, ~(1 << 8));
 217
 218        /* boot up the VCPU */
 219        WREG32(UVD_SOFT_RESET, 0);
 220        mdelay(10);
 221
 222        WREG32_P(UVD_RB_ARB_CTRL, 0, ~(1 << 3));
 223
 224        for (i = 0; i < 10; ++i) {
 225                uint32_t status;
 226                for (j = 0; j < 100; ++j) {
 227                        status = RREG32(UVD_STATUS);
 228                        if (status & 2)
 229                                break;
 230                        mdelay(10);
 231                }
 232                r = 0;
 233                if (status & 2)
 234                        break;
 235
 236                DRM_ERROR("UVD not responding, trying to reset the VCPU!!!\n");
 237                WREG32_P(UVD_SOFT_RESET, VCPU_SOFT_RESET, ~VCPU_SOFT_RESET);
 238                mdelay(10);
 239                WREG32_P(UVD_SOFT_RESET, 0, ~VCPU_SOFT_RESET);
 240                mdelay(10);
 241                r = -1;
 242        }
 243
 244        if (r) {
 245                DRM_ERROR("UVD not responding, giving up!!!\n");
 246                return r;
 247        }
 248
 249        /* enable interupt */
 250        WREG32_P(UVD_MASTINT_EN, 3<<1, ~(3 << 1));
 251
 252        /* force RBC into idle state */
 253        WREG32(UVD_RBC_RB_CNTL, 0x11010101);
 254
 255        /* Set the write pointer delay */
 256        WREG32(UVD_RBC_RB_WPTR_CNTL, 0);
 257
 258        /* programm the 4GB memory segment for rptr and ring buffer */
 259        WREG32(UVD_LMI_EXT40_ADDR, upper_32_bits(ring->gpu_addr) |
 260                                   (0x7 << 16) | (0x1 << 31));
 261
 262        /* Initialize the ring buffer's read and write pointers */
 263        WREG32(UVD_RBC_RB_RPTR, 0x0);
 264
 265        ring->wptr = ring->rptr = RREG32(UVD_RBC_RB_RPTR);
 266        WREG32(UVD_RBC_RB_WPTR, ring->wptr);
 267
 268        /* set the ring address */
 269        WREG32(UVD_RBC_RB_BASE, ring->gpu_addr);
 270
 271        /* Set ring buffer size */
 272        rb_bufsz = order_base_2(ring->ring_size);
 273        rb_bufsz = (0x1 << 8) | rb_bufsz;
 274        WREG32_P(UVD_RBC_RB_CNTL, rb_bufsz, ~0x11f1f);
 275
 276        return 0;
 277}
 278
 279/**
 280 * uvd_v1_0_stop - stop UVD block
 281 *
 282 * @rdev: radeon_device pointer
 283 *
 284 * stop the UVD block
 285 */
 286void uvd_v1_0_stop(struct radeon_device *rdev)
 287{
 288        /* force RBC into idle state */
 289        WREG32(UVD_RBC_RB_CNTL, 0x11010101);
 290
 291        /* Stall UMC and register bus before resetting VCPU */
 292        WREG32_P(UVD_LMI_CTRL2, 1 << 8, ~(1 << 8));
 293        WREG32_P(UVD_RB_ARB_CTRL, 1 << 3, ~(1 << 3));
 294        mdelay(1);
 295
 296        /* put VCPU into reset */
 297        WREG32(UVD_SOFT_RESET, VCPU_SOFT_RESET);
 298        mdelay(5);
 299
 300        /* disable VCPU clock */
 301        WREG32(UVD_VCPU_CNTL, 0x0);
 302
 303        /* Unstall UMC and register bus */
 304        WREG32_P(UVD_LMI_CTRL2, 0, ~(1 << 8));
 305        WREG32_P(UVD_RB_ARB_CTRL, 0, ~(1 << 3));
 306}
 307
 308/**
 309 * uvd_v1_0_ring_test - register write test
 310 *
 311 * @rdev: radeon_device pointer
 312 * @ring: radeon_ring pointer
 313 *
 314 * Test if we can successfully write to the context register
 315 */
 316int uvd_v1_0_ring_test(struct radeon_device *rdev, struct radeon_ring *ring)
 317{
 318        uint32_t tmp = 0;
 319        unsigned i;
 320        int r;
 321
 322        WREG32(UVD_CONTEXT_ID, 0xCAFEDEAD);
 323        r = radeon_ring_lock(rdev, ring, 3);
 324        if (r) {
 325                DRM_ERROR("radeon: cp failed to lock ring %d (%d).\n",
 326                          ring->idx, r);
 327                return r;
 328        }
 329        radeon_ring_write(ring, PACKET0(UVD_CONTEXT_ID, 0));
 330        radeon_ring_write(ring, 0xDEADBEEF);
 331        radeon_ring_unlock_commit(rdev, ring);
 332        for (i = 0; i < rdev->usec_timeout; i++) {
 333                tmp = RREG32(UVD_CONTEXT_ID);
 334                if (tmp == 0xDEADBEEF)
 335                        break;
 336                DRM_UDELAY(1);
 337        }
 338
 339        if (i < rdev->usec_timeout) {
 340                DRM_INFO("ring test on %d succeeded in %d usecs\n",
 341                         ring->idx, i);
 342        } else {
 343                DRM_ERROR("radeon: ring %d test failed (0x%08X)\n",
 344                          ring->idx, tmp);
 345                r = -EINVAL;
 346        }
 347        return r;
 348}
 349
 350/**
 351 * uvd_v1_0_semaphore_emit - emit semaphore command
 352 *
 353 * @rdev: radeon_device pointer
 354 * @ring: radeon_ring pointer
 355 * @semaphore: semaphore to emit commands for
 356 * @emit_wait: true if we should emit a wait command
 357 *
 358 * Emit a semaphore command (either wait or signal) to the UVD ring.
 359 */
 360void uvd_v1_0_semaphore_emit(struct radeon_device *rdev,
 361                             struct radeon_ring *ring,
 362                             struct radeon_semaphore *semaphore,
 363                             bool emit_wait)
 364{
 365        uint64_t addr = semaphore->gpu_addr;
 366
 367        radeon_ring_write(ring, PACKET0(UVD_SEMA_ADDR_LOW, 0));
 368        radeon_ring_write(ring, (addr >> 3) & 0x000FFFFF);
 369
 370        radeon_ring_write(ring, PACKET0(UVD_SEMA_ADDR_HIGH, 0));
 371        radeon_ring_write(ring, (addr >> 23) & 0x000FFFFF);
 372
 373        radeon_ring_write(ring, PACKET0(UVD_SEMA_CMD, 0));
 374        radeon_ring_write(ring, emit_wait ? 1 : 0);
 375}
 376
 377/**
 378 * uvd_v1_0_ib_execute - execute indirect buffer
 379 *
 380 * @rdev: radeon_device pointer
 381 * @ib: indirect buffer to execute
 382 *
 383 * Write ring commands to execute the indirect buffer
 384 */
 385void uvd_v1_0_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib)
 386{
 387        struct radeon_ring *ring = &rdev->ring[ib->ring];
 388
 389        radeon_ring_write(ring, PACKET0(UVD_RBC_IB_BASE, 0));
 390        radeon_ring_write(ring, ib->gpu_addr);
 391        radeon_ring_write(ring, PACKET0(UVD_RBC_IB_SIZE, 0));
 392        radeon_ring_write(ring, ib->length_dw);
 393}
 394
 395/**
 396 * uvd_v1_0_ib_test - test ib execution
 397 *
 398 * @rdev: radeon_device pointer
 399 * @ring: radeon_ring pointer
 400 *
 401 * Test if we can successfully execute an IB
 402 */
 403int uvd_v1_0_ib_test(struct radeon_device *rdev, struct radeon_ring *ring)
 404{
 405        struct radeon_fence *fence = NULL;
 406        int r;
 407
 408        r = radeon_set_uvd_clocks(rdev, 53300, 40000);
 409        if (r) {
 410                DRM_ERROR("radeon: failed to raise UVD clocks (%d).\n", r);
 411                return r;
 412        }
 413
 414        r = radeon_uvd_get_create_msg(rdev, ring->idx, 1, NULL);
 415        if (r) {
 416                DRM_ERROR("radeon: failed to get create msg (%d).\n", r);
 417                goto error;
 418        }
 419
 420        r = radeon_uvd_get_destroy_msg(rdev, ring->idx, 1, &fence);
 421        if (r) {
 422                DRM_ERROR("radeon: failed to get destroy ib (%d).\n", r);
 423                goto error;
 424        }
 425
 426        r = radeon_fence_wait(fence, false);
 427        if (r) {
 428                DRM_ERROR("radeon: fence wait failed (%d).\n", r);
 429                goto error;
 430        }
 431        DRM_INFO("ib test on ring %d succeeded\n",  ring->idx);
 432error:
 433        radeon_fence_unref(&fence);
 434        radeon_set_uvd_clocks(rdev, 0, 0);
 435        return r;
 436}
 437