/** * uvd_v5_0_ring_test_ib - test ib execution * * @ring: amdgpu_ring pointer * * Test if we can successfully execute an IB */ static int uvd_v5_0_ring_test_ib(struct amdgpu_ring *ring) { struct amdgpu_device *adev = ring->adev; struct fence *fence = NULL; int r; r = amdgpu_asic_set_uvd_clocks(adev, 53300, 40000); if (r) { DRM_ERROR("amdgpu: failed to raise UVD clocks (%d).\n", r); return r; } r = amdgpu_uvd_get_create_msg(ring, 1, NULL); if (r) { DRM_ERROR("amdgpu: failed to get create msg (%d).\n", r); goto error; } r = amdgpu_uvd_get_destroy_msg(ring, 1, true, &fence); if (r) { DRM_ERROR("amdgpu: failed to get destroy ib (%d).\n", r); goto error; } r = fence_wait(fence, false); if (r) { DRM_ERROR("amdgpu: fence wait failed (%d).\n", r); goto error; } DRM_INFO("ib test on ring %d succeeded\n", ring->idx); error: fence_put(fence); amdgpu_asic_set_uvd_clocks(adev, 0, 0); return r; }
/** * uvd_v5_0_hw_init - start and test UVD block * * @adev: amdgpu_device pointer * * Initialize the hardware, boot up the VCPU and do some testing */ static int uvd_v5_0_hw_init(void *handle) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; struct amdgpu_ring *ring = &adev->uvd.ring; uint32_t tmp; int r; /* raise clocks while booting up the VCPU */ amdgpu_asic_set_uvd_clocks(adev, 53300, 40000); r = uvd_v5_0_start(adev); if (r) goto done; ring->ready = true; r = amdgpu_ring_test_ring(ring); if (r) { ring->ready = false; goto done; } r = amdgpu_ring_alloc(ring, 10); if (r) { DRM_ERROR("amdgpu: ring failed to lock UVD ring (%d).\n", r); goto done; } tmp = PACKET0(mmUVD_SEMA_WAIT_FAULT_TIMEOUT_CNTL, 0); amdgpu_ring_write(ring, tmp); amdgpu_ring_write(ring, 0xFFFFF); tmp = PACKET0(mmUVD_SEMA_WAIT_INCOMPLETE_TIMEOUT_CNTL, 0); amdgpu_ring_write(ring, tmp); amdgpu_ring_write(ring, 0xFFFFF); tmp = PACKET0(mmUVD_SEMA_SIGNAL_INCOMPLETE_TIMEOUT_CNTL, 0); amdgpu_ring_write(ring, tmp); amdgpu_ring_write(ring, 0xFFFFF); /* Clear timeout status bits */ amdgpu_ring_write(ring, PACKET0(mmUVD_SEMA_TIMEOUT_STATUS, 0)); amdgpu_ring_write(ring, 0x8); amdgpu_ring_write(ring, PACKET0(mmUVD_SEMA_CNTL, 0)); amdgpu_ring_write(ring, 3); amdgpu_ring_commit(ring); done: /* lower clocks again */ amdgpu_asic_set_uvd_clocks(adev, 0, 0); if (!r) DRM_INFO("UVD initialized successfully.\n"); return r; }
/** * uvd_v5_0_hw_init - start and test UVD block * * @adev: amdgpu_device pointer * * Initialize the hardware, boot up the VCPU and do some testing */ static int uvd_v5_0_hw_init(void *handle) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; struct amdgpu_ring *ring = &adev->uvd.ring; uint32_t tmp; int r; amdgpu_asic_set_uvd_clocks(adev, 10000, 10000); uvd_v5_0_set_clockgating_state(adev, AMD_CG_STATE_UNGATE); uvd_v5_0_enable_mgcg(adev, true); ring->ready = true; r = amdgpu_ring_test_ring(ring); if (r) { ring->ready = false; goto done; } r = amdgpu_ring_alloc(ring, 10); if (r) { DRM_ERROR("amdgpu: ring failed to lock UVD ring (%d).\n", r); goto done; } tmp = PACKET0(mmUVD_SEMA_WAIT_FAULT_TIMEOUT_CNTL, 0); amdgpu_ring_write(ring, tmp); amdgpu_ring_write(ring, 0xFFFFF); tmp = PACKET0(mmUVD_SEMA_WAIT_INCOMPLETE_TIMEOUT_CNTL, 0); amdgpu_ring_write(ring, tmp); amdgpu_ring_write(ring, 0xFFFFF); tmp = PACKET0(mmUVD_SEMA_SIGNAL_INCOMPLETE_TIMEOUT_CNTL, 0); amdgpu_ring_write(ring, tmp); amdgpu_ring_write(ring, 0xFFFFF); /* Clear timeout status bits */ amdgpu_ring_write(ring, PACKET0(mmUVD_SEMA_TIMEOUT_STATUS, 0)); amdgpu_ring_write(ring, 0x8); amdgpu_ring_write(ring, PACKET0(mmUVD_SEMA_CNTL, 0)); amdgpu_ring_write(ring, 3); amdgpu_ring_commit(ring); done: if (!r) DRM_INFO("UVD initialized successfully.\n"); return r; }
/** * uvd_v6_0_hw_init - start and test UVD block * * @adev: amdgpu_device pointer * * Initialize the hardware, boot up the VCPU and do some testing */ static int uvd_v6_0_hw_init(void *handle) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; struct amdgpu_ring *ring = &adev->uvd.inst->ring; uint32_t tmp; int i, r; amdgpu_asic_set_uvd_clocks(adev, 10000, 10000); uvd_v6_0_set_clockgating_state(adev, AMD_CG_STATE_UNGATE); uvd_v6_0_enable_mgcg(adev, true); r = amdgpu_ring_test_helper(ring); if (r) goto done; r = amdgpu_ring_alloc(ring, 10); if (r) { DRM_ERROR("amdgpu: ring failed to lock UVD ring (%d).\n", r); goto done; } tmp = PACKET0(mmUVD_SEMA_WAIT_FAULT_TIMEOUT_CNTL, 0); amdgpu_ring_write(ring, tmp); amdgpu_ring_write(ring, 0xFFFFF); tmp = PACKET0(mmUVD_SEMA_WAIT_INCOMPLETE_TIMEOUT_CNTL, 0); amdgpu_ring_write(ring, tmp); amdgpu_ring_write(ring, 0xFFFFF); tmp = PACKET0(mmUVD_SEMA_SIGNAL_INCOMPLETE_TIMEOUT_CNTL, 0); amdgpu_ring_write(ring, tmp); amdgpu_ring_write(ring, 0xFFFFF); /* Clear timeout status bits */ amdgpu_ring_write(ring, PACKET0(mmUVD_SEMA_TIMEOUT_STATUS, 0)); amdgpu_ring_write(ring, 0x8); amdgpu_ring_write(ring, PACKET0(mmUVD_SEMA_CNTL, 0)); amdgpu_ring_write(ring, 3); amdgpu_ring_commit(ring); if (uvd_v6_0_enc_support(adev)) { for (i = 0; i < adev->uvd.num_enc_rings; ++i) { ring = &adev->uvd.inst->ring_enc[i]; r = amdgpu_ring_test_helper(ring); if (r) goto done; } } done: if (!r) { if (uvd_v6_0_enc_support(adev)) DRM_INFO("UVD and UVD ENC initialized successfully.\n"); else DRM_INFO("UVD initialized successfully.\n"); } return r; }
/** * uvd_v5_0_start - start UVD block * * @adev: amdgpu_device pointer * * Setup and start the UVD block */ static int uvd_v5_0_start(struct amdgpu_device *adev) { struct amdgpu_ring *ring = &adev->uvd.ring; uint32_t rb_bufsz, tmp; uint32_t lmi_swap_cntl; uint32_t mp_swap_cntl; int i, j, r; /*disable DPG */ WREG32_P(mmUVD_POWER_STATUS, 0, ~(1 << 2)); /* disable byte swapping */ lmi_swap_cntl = 0; mp_swap_cntl = 0; uvd_v5_0_mc_resume(adev); amdgpu_asic_set_uvd_clocks(adev, 10000, 10000); uvd_v5_0_set_clockgating_state(adev, AMD_CG_STATE_UNGATE); uvd_v5_0_enable_mgcg(adev, true); /* disable interupt */ WREG32_P(mmUVD_MASTINT_EN, 0, ~(1 << 1)); /* stall UMC and register bus before resetting VCPU */ WREG32_P(mmUVD_LMI_CTRL2, 1 << 8, ~(1 << 8)); mdelay(1); /* put LMI, VCPU, RBC etc... into reset */ WREG32(mmUVD_SOFT_RESET, UVD_SOFT_RESET__LMI_SOFT_RESET_MASK | UVD_SOFT_RESET__VCPU_SOFT_RESET_MASK | UVD_SOFT_RESET__LBSI_SOFT_RESET_MASK | UVD_SOFT_RESET__RBC_SOFT_RESET_MASK | UVD_SOFT_RESET__CSM_SOFT_RESET_MASK | UVD_SOFT_RESET__CXW_SOFT_RESET_MASK | UVD_SOFT_RESET__TAP_SOFT_RESET_MASK | UVD_SOFT_RESET__LMI_UMC_SOFT_RESET_MASK); mdelay(5); /* take UVD block out of reset */ WREG32_P(mmSRBM_SOFT_RESET, 0, ~SRBM_SOFT_RESET__SOFT_RESET_UVD_MASK); mdelay(5); /* initialize UVD memory controller */ WREG32(mmUVD_LMI_CTRL, 0x40 | (1 << 8) | (1 << 13) | (1 << 21) | (1 << 9) | (1 << 20)); #ifdef __BIG_ENDIAN /* swap (8 in 32) RB and IB */ lmi_swap_cntl = 0xa; mp_swap_cntl = 0; #endif WREG32(mmUVD_LMI_SWAP_CNTL, lmi_swap_cntl); WREG32(mmUVD_MP_SWAP_CNTL, mp_swap_cntl); WREG32(mmUVD_MPC_SET_MUXA0, 0x40c2040); WREG32(mmUVD_MPC_SET_MUXA1, 0x0); WREG32(mmUVD_MPC_SET_MUXB0, 0x40c2040); WREG32(mmUVD_MPC_SET_MUXB1, 0x0); WREG32(mmUVD_MPC_SET_ALU, 0); WREG32(mmUVD_MPC_SET_MUX, 0x88); /* take all subblocks out of reset, except VCPU */ WREG32(mmUVD_SOFT_RESET, UVD_SOFT_RESET__VCPU_SOFT_RESET_MASK); mdelay(5); /* enable VCPU clock */ WREG32(mmUVD_VCPU_CNTL, 1 << 9); /* enable UMC */ WREG32_P(mmUVD_LMI_CTRL2, 0, ~(1 << 8)); /* boot up the VCPU */ WREG32(mmUVD_SOFT_RESET, 0); mdelay(10); for (i = 0; i < 10; ++i) { uint32_t status; for (j = 0; j < 100; ++j) { status = RREG32(mmUVD_STATUS); if (status & 2) break; mdelay(10); } r = 0; if (status & 2) break; DRM_ERROR("UVD not responding, trying to reset the VCPU!!!\n"); WREG32_P(mmUVD_SOFT_RESET, UVD_SOFT_RESET__VCPU_SOFT_RESET_MASK, ~UVD_SOFT_RESET__VCPU_SOFT_RESET_MASK); mdelay(10); WREG32_P(mmUVD_SOFT_RESET, 0, ~UVD_SOFT_RESET__VCPU_SOFT_RESET_MASK); mdelay(10); r = -1; } if (r) { DRM_ERROR("UVD not responding, giving up!!!\n"); return r; } /* enable master interrupt */ WREG32_P(mmUVD_MASTINT_EN, 3 << 1, ~(3 << 1)); /* clear the bit 4 of UVD_STATUS */ WREG32_P(mmUVD_STATUS, 0, ~(2 << 1)); rb_bufsz = order_base_2(ring->ring_size); tmp = 0; tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_BUFSZ, rb_bufsz); tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_BLKSZ, 1); tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_NO_FETCH, 1); tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_WPTR_POLL_EN, 0); tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_NO_UPDATE, 1); tmp = REG_SET_FIELD(tmp, UVD_RBC_RB_CNTL, RB_RPTR_WR_EN, 1); /* force RBC into idle state */ WREG32(mmUVD_RBC_RB_CNTL, tmp); /* set the write pointer delay */ WREG32(mmUVD_RBC_RB_WPTR_CNTL, 0); /* set the wb address */ WREG32(mmUVD_RBC_RB_RPTR_ADDR, (upper_32_bits(ring->gpu_addr) >> 2)); /* programm the RB_BASE for ring buffer */ WREG32(mmUVD_LMI_RBC_RB_64BIT_BAR_LOW, lower_32_bits(ring->gpu_addr)); WREG32(mmUVD_LMI_RBC_RB_64BIT_BAR_HIGH, upper_32_bits(ring->gpu_addr)); /* Initialize the ring buffer's read and write pointers */ WREG32(mmUVD_RBC_RB_RPTR, 0); ring->wptr = RREG32(mmUVD_RBC_RB_RPTR); WREG32(mmUVD_RBC_RB_WPTR, ring->wptr); WREG32_P(mmUVD_RBC_RB_CNTL, 0, ~UVD_RBC_RB_CNTL__RB_NO_FETCH_MASK); return 0; }