diff options
| author | Christian König <christian.koenig@amd.com> | 2013-05-23 06:10:04 -0400 |
|---|---|---|
| committer | Christian König <christian.koenig@amd.com> | 2014-02-18 10:11:22 -0500 |
| commit | d93f79376f210e0b19da57a3dc841ba332daa9d0 (patch) | |
| tree | 2fe1ee891972b9da1d6d3b743ddc0198e17fab8c | |
| parent | 1c61eae469e0d1d2fb9d7b77f51ca50c1f8f3ce9 (diff) | |
drm/radeon: initial VCE support v4
Only VCE 2.0 support so far.
v2: squashing multiple patches into this one
v3: add IRQ support for CIK, major cleanups,
basic code documentation
v4: remove HAINAN from chipset list
Signed-off-by: Christian König <christian.koenig@amd.com>
| -rw-r--r-- | drivers/gpu/drm/radeon/Makefile | 6 | ||||
| -rw-r--r-- | drivers/gpu/drm/radeon/cik.c | 60 | ||||
| -rw-r--r-- | drivers/gpu/drm/radeon/cikd.h | 33 | ||||
| -rw-r--r-- | drivers/gpu/drm/radeon/radeon.h | 56 | ||||
| -rw-r--r-- | drivers/gpu/drm/radeon/radeon_asic.c | 17 | ||||
| -rw-r--r-- | drivers/gpu/drm/radeon/radeon_asic.h | 13 | ||||
| -rw-r--r-- | drivers/gpu/drm/radeon/radeon_cs.c | 4 | ||||
| -rw-r--r-- | drivers/gpu/drm/radeon/radeon_kms.c | 1 | ||||
| -rw-r--r-- | drivers/gpu/drm/radeon/radeon_ring.c | 4 | ||||
| -rw-r--r-- | drivers/gpu/drm/radeon/radeon_test.c | 39 | ||||
| -rw-r--r-- | drivers/gpu/drm/radeon/radeon_vce.c | 588 | ||||
| -rw-r--r-- | drivers/gpu/drm/radeon/sid.h | 47 | ||||
| -rw-r--r-- | drivers/gpu/drm/radeon/vce_v1_0.c | 187 | ||||
| -rw-r--r-- | drivers/gpu/drm/radeon/vce_v2_0.c | 70 | ||||
| -rw-r--r-- | include/uapi/drm/radeon_drm.h | 1 |
15 files changed, 1117 insertions, 9 deletions
diff --git a/drivers/gpu/drm/radeon/Makefile b/drivers/gpu/drm/radeon/Makefile index 306364a1ecda..ed60caa32518 100644 --- a/drivers/gpu/drm/radeon/Makefile +++ b/drivers/gpu/drm/radeon/Makefile | |||
| @@ -99,6 +99,12 @@ radeon-y += \ | |||
| 99 | uvd_v3_1.o \ | 99 | uvd_v3_1.o \ |
| 100 | uvd_v4_2.o | 100 | uvd_v4_2.o |
| 101 | 101 | ||
| 102 | # add VCE block | ||
| 103 | radeon-y += \ | ||
| 104 | radeon_vce.o \ | ||
| 105 | vce_v1_0.o \ | ||
| 106 | vce_v2_0.o \ | ||
| 107 | |||
| 102 | radeon-$(CONFIG_COMPAT) += radeon_ioc32.o | 108 | radeon-$(CONFIG_COMPAT) += radeon_ioc32.o |
| 103 | radeon-$(CONFIG_VGA_SWITCHEROO) += radeon_atpx_handler.o | 109 | radeon-$(CONFIG_VGA_SWITCHEROO) += radeon_atpx_handler.o |
| 104 | radeon-$(CONFIG_ACPI) += radeon_acpi.o | 110 | radeon-$(CONFIG_ACPI) += radeon_acpi.o |
diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c index e6419ca7cd37..be6eb4d91284 100644 --- a/drivers/gpu/drm/radeon/cik.c +++ b/drivers/gpu/drm/radeon/cik.c | |||
| @@ -7490,6 +7490,20 @@ restart_ih: | |||
| 7490 | /* reset addr and status */ | 7490 | /* reset addr and status */ |
| 7491 | WREG32_P(VM_CONTEXT1_CNTL2, 1, ~1); | 7491 | WREG32_P(VM_CONTEXT1_CNTL2, 1, ~1); |
| 7492 | break; | 7492 | break; |
| 7493 | case 167: /* VCE */ | ||
| 7494 | DRM_DEBUG("IH: VCE int: 0x%08x\n", src_data); | ||
| 7495 | switch (src_data) { | ||
| 7496 | case 0: | ||
| 7497 | radeon_fence_process(rdev, TN_RING_TYPE_VCE1_INDEX); | ||
| 7498 | break; | ||
| 7499 | case 1: | ||
| 7500 | radeon_fence_process(rdev, TN_RING_TYPE_VCE2_INDEX); | ||
| 7501 | break; | ||
| 7502 | default: | ||
| 7503 | DRM_ERROR("Unhandled interrupt: %d %d\n", src_id, src_data); | ||
| 7504 | break; | ||
| 7505 | } | ||
| 7506 | break; | ||
| 7493 | case 176: /* GFX RB CP_INT */ | 7507 | case 176: /* GFX RB CP_INT */ |
| 7494 | case 177: /* GFX IB CP_INT */ | 7508 | case 177: /* GFX IB CP_INT */ |
| 7495 | radeon_fence_process(rdev, RADEON_RING_TYPE_GFX_INDEX); | 7509 | radeon_fence_process(rdev, RADEON_RING_TYPE_GFX_INDEX); |
| @@ -7789,6 +7803,22 @@ static int cik_startup(struct radeon_device *rdev) | |||
| 7789 | if (r) | 7803 | if (r) |
| 7790 | rdev->ring[R600_RING_TYPE_UVD_INDEX].ring_size = 0; | 7804 | rdev->ring[R600_RING_TYPE_UVD_INDEX].ring_size = 0; |
| 7791 | 7805 | ||
| 7806 | r = radeon_vce_resume(rdev); | ||
| 7807 | if (!r) { | ||
| 7808 | r = vce_v2_0_resume(rdev); | ||
| 7809 | if (!r) | ||
| 7810 | r = radeon_fence_driver_start_ring(rdev, | ||
| 7811 | TN_RING_TYPE_VCE1_INDEX); | ||
| 7812 | if (!r) | ||
| 7813 | r = radeon_fence_driver_start_ring(rdev, | ||
| 7814 | TN_RING_TYPE_VCE2_INDEX); | ||
| 7815 | } | ||
| 7816 | if (r) { | ||
| 7817 | dev_err(rdev->dev, "VCE init error (%d).\n", r); | ||
| 7818 | rdev->ring[TN_RING_TYPE_VCE1_INDEX].ring_size = 0; | ||
| 7819 | rdev->ring[TN_RING_TYPE_VCE2_INDEX].ring_size = 0; | ||
| 7820 | } | ||
| 7821 | |||
| 7792 | /* Enable IRQ */ | 7822 | /* Enable IRQ */ |
| 7793 | if (!rdev->irq.installed) { | 7823 | if (!rdev->irq.installed) { |
| 7794 | r = radeon_irq_kms_init(rdev); | 7824 | r = radeon_irq_kms_init(rdev); |
| @@ -7864,6 +7894,23 @@ static int cik_startup(struct radeon_device *rdev) | |||
| 7864 | DRM_ERROR("radeon: failed initializing UVD (%d).\n", r); | 7894 | DRM_ERROR("radeon: failed initializing UVD (%d).\n", r); |
| 7865 | } | 7895 | } |
| 7866 | 7896 | ||
| 7897 | r = -ENOENT; | ||
| 7898 | |||
| 7899 | ring = &rdev->ring[TN_RING_TYPE_VCE1_INDEX]; | ||
| 7900 | if (ring->ring_size) | ||
| 7901 | r = radeon_ring_init(rdev, ring, ring->ring_size, 0, | ||
| 7902 | VCE_CMD_NO_OP); | ||
| 7903 | |||
| 7904 | ring = &rdev->ring[TN_RING_TYPE_VCE2_INDEX]; | ||
| 7905 | if (ring->ring_size) | ||
| 7906 | r = radeon_ring_init(rdev, ring, ring->ring_size, 0, | ||
| 7907 | VCE_CMD_NO_OP); | ||
| 7908 | |||
| 7909 | if (!r) | ||
| 7910 | r = vce_v1_0_init(rdev); | ||
| 7911 | else if (r != -ENOENT) | ||
| 7912 | DRM_ERROR("radeon: failed initializing VCE (%d).\n", r); | ||
| 7913 | |||
| 7867 | r = radeon_ib_pool_init(rdev); | 7914 | r = radeon_ib_pool_init(rdev); |
| 7868 | if (r) { | 7915 | if (r) { |
| 7869 | dev_err(rdev->dev, "IB initialization failed (%d).\n", r); | 7916 | dev_err(rdev->dev, "IB initialization failed (%d).\n", r); |
| @@ -7934,6 +7981,7 @@ int cik_suspend(struct radeon_device *rdev) | |||
| 7934 | cik_sdma_enable(rdev, false); | 7981 | cik_sdma_enable(rdev, false); |
| 7935 | uvd_v1_0_fini(rdev); | 7982 | uvd_v1_0_fini(rdev); |
| 7936 | radeon_uvd_suspend(rdev); | 7983 | radeon_uvd_suspend(rdev); |
| 7984 | radeon_vce_suspend(rdev); | ||
| 7937 | cik_fini_pg(rdev); | 7985 | cik_fini_pg(rdev); |
| 7938 | cik_fini_cg(rdev); | 7986 | cik_fini_cg(rdev); |
| 7939 | cik_irq_suspend(rdev); | 7987 | cik_irq_suspend(rdev); |
| @@ -8066,6 +8114,17 @@ int cik_init(struct radeon_device *rdev) | |||
| 8066 | r600_ring_init(rdev, ring, 4096); | 8114 | r600_ring_init(rdev, ring, 4096); |
| 8067 | } | 8115 | } |
| 8068 | 8116 | ||
| 8117 | r = radeon_vce_init(rdev); | ||
| 8118 | if (!r) { | ||
| 8119 | ring = &rdev->ring[TN_RING_TYPE_VCE1_INDEX]; | ||
| 8120 | ring->ring_obj = NULL; | ||
| 8121 | r600_ring_init(rdev, ring, 4096); | ||
| 8122 | |||
| 8123 | ring = &rdev->ring[TN_RING_TYPE_VCE2_INDEX]; | ||
| 8124 | ring->ring_obj = NULL; | ||
| 8125 | r600_ring_init(rdev, ring, 4096); | ||
| 8126 | } | ||
| 8127 | |||
| 8069 | rdev->ih.ring_obj = NULL; | 8128 | rdev->ih.ring_obj = NULL; |
| 8070 | r600_ih_ring_init(rdev, 64 * 1024); | 8129 | r600_ih_ring_init(rdev, 64 * 1024); |
| 8071 | 8130 | ||
| @@ -8127,6 +8186,7 @@ void cik_fini(struct radeon_device *rdev) | |||
| 8127 | radeon_irq_kms_fini(rdev); | 8186 | radeon_irq_kms_fini(rdev); |
| 8128 | uvd_v1_0_fini(rdev); | 8187 | uvd_v1_0_fini(rdev); |
| 8129 | radeon_uvd_fini(rdev); | 8188 | radeon_uvd_fini(rdev); |
| 8189 | radeon_vce_fini(rdev); | ||
| 8130 | cik_pcie_gart_fini(rdev); | 8190 | cik_pcie_gart_fini(rdev); |
| 8131 | r600_vram_scratch_fini(rdev); | 8191 | r600_vram_scratch_fini(rdev); |
| 8132 | radeon_gem_fini(rdev); | 8192 | radeon_gem_fini(rdev); |
diff --git a/drivers/gpu/drm/radeon/cikd.h b/drivers/gpu/drm/radeon/cikd.h index 98bae9d7b74d..459ae021d91c 100644 --- a/drivers/gpu/drm/radeon/cikd.h +++ b/drivers/gpu/drm/radeon/cikd.h | |||
| @@ -2010,4 +2010,37 @@ | |||
| 2010 | /* UVD CTX indirect */ | 2010 | /* UVD CTX indirect */ |
| 2011 | #define UVD_CGC_MEM_CTRL 0xC0 | 2011 | #define UVD_CGC_MEM_CTRL 0xC0 |
| 2012 | 2012 | ||
| 2013 | /* VCE */ | ||
| 2014 | |||
| 2015 | #define VCE_VCPU_CACHE_OFFSET0 0x20024 | ||
| 2016 | #define VCE_VCPU_CACHE_SIZE0 0x20028 | ||
| 2017 | #define VCE_VCPU_CACHE_OFFSET1 0x2002c | ||
| 2018 | #define VCE_VCPU_CACHE_SIZE1 0x20030 | ||
| 2019 | #define VCE_VCPU_CACHE_OFFSET2 0x20034 | ||
| 2020 | #define VCE_VCPU_CACHE_SIZE2 0x20038 | ||
| 2021 | #define VCE_RB_RPTR2 0x20178 | ||
| 2022 | #define VCE_RB_WPTR2 0x2017c | ||
| 2023 | #define VCE_RB_RPTR 0x2018c | ||
| 2024 | #define VCE_RB_WPTR 0x20190 | ||
| 2025 | #define VCE_CLOCK_GATING_A 0x202f8 | ||
| 2026 | #define VCE_CLOCK_GATING_B 0x202fc | ||
| 2027 | #define VCE_UENC_CLOCK_GATING 0x207bc | ||
| 2028 | #define VCE_UENC_REG_CLOCK_GATING 0x207c0 | ||
| 2029 | #define VCE_SYS_INT_EN 0x21300 | ||
| 2030 | # define VCE_SYS_INT_TRAP_INTERRUPT_EN (1 << 3) | ||
| 2031 | #define VCE_LMI_CTRL2 0x21474 | ||
| 2032 | #define VCE_LMI_CTRL 0x21498 | ||
| 2033 | #define VCE_LMI_VM_CTRL 0x214a0 | ||
| 2034 | #define VCE_LMI_SWAP_CNTL 0x214b4 | ||
| 2035 | #define VCE_LMI_SWAP_CNTL1 0x214b8 | ||
| 2036 | #define VCE_LMI_CACHE_CTRL 0x214f4 | ||
| 2037 | |||
| 2038 | #define VCE_CMD_NO_OP 0x00000000 | ||
| 2039 | #define VCE_CMD_END 0x00000001 | ||
| 2040 | #define VCE_CMD_IB 0x00000002 | ||
| 2041 | #define VCE_CMD_FENCE 0x00000003 | ||
| 2042 | #define VCE_CMD_TRAP 0x00000004 | ||
| 2043 | #define VCE_CMD_IB_AUTO 0x00000005 | ||
| 2044 | #define VCE_CMD_SEMAPHORE 0x00000006 | ||
| 2045 | |||
| 2013 | #endif | 2046 | #endif |
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 024db37b1832..a58a38942c73 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h | |||
| @@ -113,19 +113,16 @@ extern int radeon_hard_reset; | |||
| 113 | #define RADEONFB_CONN_LIMIT 4 | 113 | #define RADEONFB_CONN_LIMIT 4 |
| 114 | #define RADEON_BIOS_NUM_SCRATCH 8 | 114 | #define RADEON_BIOS_NUM_SCRATCH 8 |
| 115 | 115 | ||
| 116 | /* max number of rings */ | ||
| 117 | #define RADEON_NUM_RINGS 6 | ||
| 118 | |||
| 119 | /* fence seq are set to this number when signaled */ | 116 | /* fence seq are set to this number when signaled */ |
| 120 | #define RADEON_FENCE_SIGNALED_SEQ 0LL | 117 | #define RADEON_FENCE_SIGNALED_SEQ 0LL |
| 121 | 118 | ||
| 122 | /* internal ring indices */ | 119 | /* internal ring indices */ |
| 123 | /* r1xx+ has gfx CP ring */ | 120 | /* r1xx+ has gfx CP ring */ |
| 124 | #define RADEON_RING_TYPE_GFX_INDEX 0 | 121 | #define RADEON_RING_TYPE_GFX_INDEX 0 |
| 125 | 122 | ||
| 126 | /* cayman has 2 compute CP rings */ | 123 | /* cayman has 2 compute CP rings */ |
| 127 | #define CAYMAN_RING_TYPE_CP1_INDEX 1 | 124 | #define CAYMAN_RING_TYPE_CP1_INDEX 1 |
| 128 | #define CAYMAN_RING_TYPE_CP2_INDEX 2 | 125 | #define CAYMAN_RING_TYPE_CP2_INDEX 2 |
| 129 | 126 | ||
| 130 | /* R600+ has an async dma ring */ | 127 | /* R600+ has an async dma ring */ |
| 131 | #define R600_RING_TYPE_DMA_INDEX 3 | 128 | #define R600_RING_TYPE_DMA_INDEX 3 |
| @@ -133,7 +130,14 @@ extern int radeon_hard_reset; | |||
| 133 | #define CAYMAN_RING_TYPE_DMA1_INDEX 4 | 130 | #define CAYMAN_RING_TYPE_DMA1_INDEX 4 |
| 134 | 131 | ||
| 135 | /* R600+ */ | 132 | /* R600+ */ |
| 136 | #define R600_RING_TYPE_UVD_INDEX 5 | 133 | #define R600_RING_TYPE_UVD_INDEX 5 |
| 134 | |||
| 135 | /* TN+ */ | ||
| 136 | #define TN_RING_TYPE_VCE1_INDEX 6 | ||
| 137 | #define TN_RING_TYPE_VCE2_INDEX 7 | ||
| 138 | |||
| 139 | /* max number of rings */ | ||
| 140 | #define RADEON_NUM_RINGS 8 | ||
| 137 | 141 | ||
| 138 | /* number of hw syncs before falling back on blocking */ | 142 | /* number of hw syncs before falling back on blocking */ |
| 139 | #define RADEON_NUM_SYNCS 4 | 143 | #define RADEON_NUM_SYNCS 4 |
| @@ -1591,6 +1595,42 @@ int radeon_uvd_calc_upll_dividers(struct radeon_device *rdev, | |||
| 1591 | int radeon_uvd_send_upll_ctlreq(struct radeon_device *rdev, | 1595 | int radeon_uvd_send_upll_ctlreq(struct radeon_device *rdev, |
| 1592 | unsigned cg_upll_func_cntl); | 1596 | unsigned cg_upll_func_cntl); |
| 1593 | 1597 | ||
| 1598 | /* | ||
| 1599 | * VCE | ||
| 1600 | */ | ||
| 1601 | #define RADEON_MAX_VCE_HANDLES 16 | ||
| 1602 | #define RADEON_VCE_STACK_SIZE (1024*1024) | ||
| 1603 | #define RADEON_VCE_HEAP_SIZE (4*1024*1024) | ||
| 1604 | |||
| 1605 | struct radeon_vce { | ||
| 1606 | struct radeon_bo *vcpu_bo; | ||
| 1607 | void *cpu_addr; | ||
| 1608 | uint64_t gpu_addr; | ||
| 1609 | atomic_t handles[RADEON_MAX_VCE_HANDLES]; | ||
| 1610 | struct drm_file *filp[RADEON_MAX_VCE_HANDLES]; | ||
| 1611 | }; | ||
| 1612 | |||
| 1613 | int radeon_vce_init(struct radeon_device *rdev); | ||
| 1614 | void radeon_vce_fini(struct radeon_device *rdev); | ||
| 1615 | int radeon_vce_suspend(struct radeon_device *rdev); | ||
| 1616 | int radeon_vce_resume(struct radeon_device *rdev); | ||
| 1617 | int radeon_vce_get_create_msg(struct radeon_device *rdev, int ring, | ||
| 1618 | uint32_t handle, struct radeon_fence **fence); | ||
| 1619 | int radeon_vce_get_destroy_msg(struct radeon_device *rdev, int ring, | ||
| 1620 | uint32_t handle, struct radeon_fence **fence); | ||
| 1621 | void radeon_vce_free_handles(struct radeon_device *rdev, struct drm_file *filp); | ||
| 1622 | int radeon_vce_cs_reloc(struct radeon_cs_parser *p, int lo, int hi); | ||
| 1623 | int radeon_vce_cs_parse(struct radeon_cs_parser *p); | ||
| 1624 | bool radeon_vce_semaphore_emit(struct radeon_device *rdev, | ||
| 1625 | struct radeon_ring *ring, | ||
| 1626 | struct radeon_semaphore *semaphore, | ||
| 1627 | bool emit_wait); | ||
| 1628 | void radeon_vce_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib); | ||
| 1629 | void radeon_vce_fence_emit(struct radeon_device *rdev, | ||
| 1630 | struct radeon_fence *fence); | ||
| 1631 | int radeon_vce_ring_test(struct radeon_device *rdev, struct radeon_ring *ring); | ||
| 1632 | int radeon_vce_ib_test(struct radeon_device *rdev, struct radeon_ring *ring); | ||
| 1633 | |||
| 1594 | struct r600_audio_pin { | 1634 | struct r600_audio_pin { |
| 1595 | int channels; | 1635 | int channels; |
| 1596 | int rate; | 1636 | int rate; |
| @@ -2186,6 +2226,7 @@ struct radeon_device { | |||
| 2186 | struct radeon_gem gem; | 2226 | struct radeon_gem gem; |
| 2187 | struct radeon_pm pm; | 2227 | struct radeon_pm pm; |
| 2188 | struct radeon_uvd uvd; | 2228 | struct radeon_uvd uvd; |
| 2229 | struct radeon_vce vce; | ||
| 2189 | uint32_t bios_scratch[RADEON_BIOS_NUM_SCRATCH]; | 2230 | uint32_t bios_scratch[RADEON_BIOS_NUM_SCRATCH]; |
| 2190 | struct radeon_wb wb; | 2231 | struct radeon_wb wb; |
| 2191 | struct radeon_dummy_page dummy_page; | 2232 | struct radeon_dummy_page dummy_page; |
| @@ -2205,6 +2246,7 @@ struct radeon_device { | |||
| 2205 | const struct firmware *sdma_fw; /* CIK SDMA firmware */ | 2246 | const struct firmware *sdma_fw; /* CIK SDMA firmware */ |
| 2206 | const struct firmware *smc_fw; /* SMC firmware */ | 2247 | const struct firmware *smc_fw; /* SMC firmware */ |
| 2207 | const struct firmware *uvd_fw; /* UVD firmware */ | 2248 | const struct firmware *uvd_fw; /* UVD firmware */ |
| 2249 | const struct firmware *vce_fw; /* VCE firmware */ | ||
| 2208 | struct r600_vram_scratch vram_scratch; | 2250 | struct r600_vram_scratch vram_scratch; |
| 2209 | int msi_enabled; /* msi enabled */ | 2251 | int msi_enabled; /* msi enabled */ |
| 2210 | struct r600_ih ih; /* r6/700 interrupt ring */ | 2252 | struct r600_ih ih; /* r6/700 interrupt ring */ |
diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c index dda02bfc10a4..4f059b2c05fb 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.c +++ b/drivers/gpu/drm/radeon/radeon_asic.c | |||
| @@ -1987,6 +1987,19 @@ static struct radeon_asic_ring ci_dma_ring = { | |||
| 1987 | .set_wptr = &cik_sdma_set_wptr, | 1987 | .set_wptr = &cik_sdma_set_wptr, |
| 1988 | }; | 1988 | }; |
| 1989 | 1989 | ||
| 1990 | static struct radeon_asic_ring ci_vce_ring = { | ||
| 1991 | .ib_execute = &radeon_vce_ib_execute, | ||
| 1992 | .emit_fence = &radeon_vce_fence_emit, | ||
| 1993 | .emit_semaphore = &radeon_vce_semaphore_emit, | ||
| 1994 | .cs_parse = &radeon_vce_cs_parse, | ||
| 1995 | .ring_test = &radeon_vce_ring_test, | ||
| 1996 | .ib_test = &radeon_vce_ib_test, | ||
| 1997 | .is_lockup = &radeon_ring_test_lockup, | ||
| 1998 | .get_rptr = &vce_v1_0_get_rptr, | ||
| 1999 | .get_wptr = &vce_v1_0_get_wptr, | ||
| 2000 | .set_wptr = &vce_v1_0_set_wptr, | ||
| 2001 | }; | ||
| 2002 | |||
| 1990 | static struct radeon_asic ci_asic = { | 2003 | static struct radeon_asic ci_asic = { |
| 1991 | .init = &cik_init, | 2004 | .init = &cik_init, |
| 1992 | .fini = &cik_fini, | 2005 | .fini = &cik_fini, |
| @@ -2015,6 +2028,8 @@ static struct radeon_asic ci_asic = { | |||
| 2015 | [R600_RING_TYPE_DMA_INDEX] = &ci_dma_ring, | 2028 | [R600_RING_TYPE_DMA_INDEX] = &ci_dma_ring, |
| 2016 | [CAYMAN_RING_TYPE_DMA1_INDEX] = &ci_dma_ring, | 2029 | [CAYMAN_RING_TYPE_DMA1_INDEX] = &ci_dma_ring, |
| 2017 | [R600_RING_TYPE_UVD_INDEX] = &cayman_uvd_ring, | 2030 | [R600_RING_TYPE_UVD_INDEX] = &cayman_uvd_ring, |
| 2031 | [TN_RING_TYPE_VCE1_INDEX] = &ci_vce_ring, | ||
| 2032 | [TN_RING_TYPE_VCE2_INDEX] = &ci_vce_ring, | ||
| 2018 | }, | 2033 | }, |
| 2019 | .irq = { | 2034 | .irq = { |
| 2020 | .set = &cik_irq_set, | 2035 | .set = &cik_irq_set, |
| @@ -2117,6 +2132,8 @@ static struct radeon_asic kv_asic = { | |||
| 2117 | [R600_RING_TYPE_DMA_INDEX] = &ci_dma_ring, | 2132 | [R600_RING_TYPE_DMA_INDEX] = &ci_dma_ring, |
| 2118 | [CAYMAN_RING_TYPE_DMA1_INDEX] = &ci_dma_ring, | 2133 | [CAYMAN_RING_TYPE_DMA1_INDEX] = &ci_dma_ring, |
| 2119 | [R600_RING_TYPE_UVD_INDEX] = &cayman_uvd_ring, | 2134 | [R600_RING_TYPE_UVD_INDEX] = &cayman_uvd_ring, |
| 2135 | [TN_RING_TYPE_VCE1_INDEX] = &ci_vce_ring, | ||
| 2136 | [TN_RING_TYPE_VCE2_INDEX] = &ci_vce_ring, | ||
| 2120 | }, | 2137 | }, |
| 2121 | .irq = { | 2138 | .irq = { |
| 2122 | .set = &cik_irq_set, | 2139 | .set = &cik_irq_set, |
diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h index ae637cfda783..13f87bf5254b 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.h +++ b/drivers/gpu/drm/radeon/radeon_asic.h | |||
| @@ -863,4 +863,17 @@ bool uvd_v3_1_semaphore_emit(struct radeon_device *rdev, | |||
| 863 | /* uvd v4.2 */ | 863 | /* uvd v4.2 */ |
| 864 | int uvd_v4_2_resume(struct radeon_device *rdev); | 864 | int uvd_v4_2_resume(struct radeon_device *rdev); |
| 865 | 865 | ||
| 866 | /* vce v1.0 */ | ||
| 867 | uint32_t vce_v1_0_get_rptr(struct radeon_device *rdev, | ||
| 868 | struct radeon_ring *ring); | ||
| 869 | uint32_t vce_v1_0_get_wptr(struct radeon_device *rdev, | ||
| 870 | struct radeon_ring *ring); | ||
| 871 | void vce_v1_0_set_wptr(struct radeon_device *rdev, | ||
| 872 | struct radeon_ring *ring); | ||
| 873 | int vce_v1_0_init(struct radeon_device *rdev); | ||
| 874 | int vce_v1_0_start(struct radeon_device *rdev); | ||
| 875 | |||
| 876 | /* vce v2.0 */ | ||
| 877 | int vce_v2_0_resume(struct radeon_device *rdev); | ||
| 878 | |||
| 866 | #endif | 879 | #endif |
diff --git a/drivers/gpu/drm/radeon/radeon_cs.c b/drivers/gpu/drm/radeon/radeon_cs.c index dfb5a1db87d4..701ee7981b5c 100644 --- a/drivers/gpu/drm/radeon/radeon_cs.c +++ b/drivers/gpu/drm/radeon/radeon_cs.c | |||
| @@ -147,6 +147,10 @@ static int radeon_cs_get_ring(struct radeon_cs_parser *p, u32 ring, s32 priority | |||
| 147 | case RADEON_CS_RING_UVD: | 147 | case RADEON_CS_RING_UVD: |
| 148 | p->ring = R600_RING_TYPE_UVD_INDEX; | 148 | p->ring = R600_RING_TYPE_UVD_INDEX; |
| 149 | break; | 149 | break; |
| 150 | case RADEON_CS_RING_VCE: | ||
| 151 | /* TODO: only use the low priority ring for now */ | ||
| 152 | p->ring = TN_RING_TYPE_VCE1_INDEX; | ||
| 153 | break; | ||
| 150 | } | 154 | } |
| 151 | return 0; | 155 | return 0; |
| 152 | } | 156 | } |
diff --git a/drivers/gpu/drm/radeon/radeon_kms.c b/drivers/gpu/drm/radeon/radeon_kms.c index 114d1672d616..0e078afc5db7 100644 --- a/drivers/gpu/drm/radeon/radeon_kms.c +++ b/drivers/gpu/drm/radeon/radeon_kms.c | |||
| @@ -610,6 +610,7 @@ void radeon_driver_preclose_kms(struct drm_device *dev, | |||
| 610 | if (rdev->cmask_filp == file_priv) | 610 | if (rdev->cmask_filp == file_priv) |
| 611 | rdev->cmask_filp = NULL; | 611 | rdev->cmask_filp = NULL; |
| 612 | radeon_uvd_free_handles(rdev, file_priv); | 612 | radeon_uvd_free_handles(rdev, file_priv); |
| 613 | radeon_vce_free_handles(rdev, file_priv); | ||
| 613 | } | 614 | } |
| 614 | 615 | ||
| 615 | /* | 616 | /* |
diff --git a/drivers/gpu/drm/radeon/radeon_ring.c b/drivers/gpu/drm/radeon/radeon_ring.c index 15e44a7281ab..d2980b03d1ad 100644 --- a/drivers/gpu/drm/radeon/radeon_ring.c +++ b/drivers/gpu/drm/radeon/radeon_ring.c | |||
| @@ -814,6 +814,8 @@ static int cayman_cp2_index = CAYMAN_RING_TYPE_CP2_INDEX; | |||
| 814 | static int radeon_dma1_index = R600_RING_TYPE_DMA_INDEX; | 814 | static int radeon_dma1_index = R600_RING_TYPE_DMA_INDEX; |
| 815 | static int radeon_dma2_index = CAYMAN_RING_TYPE_DMA1_INDEX; | 815 | static int radeon_dma2_index = CAYMAN_RING_TYPE_DMA1_INDEX; |
| 816 | static int r600_uvd_index = R600_RING_TYPE_UVD_INDEX; | 816 | static int r600_uvd_index = R600_RING_TYPE_UVD_INDEX; |
| 817 | static int si_vce1_index = TN_RING_TYPE_VCE1_INDEX; | ||
| 818 | static int si_vce2_index = TN_RING_TYPE_VCE2_INDEX; | ||
| 817 | 819 | ||
| 818 | static struct drm_info_list radeon_debugfs_ring_info_list[] = { | 820 | static struct drm_info_list radeon_debugfs_ring_info_list[] = { |
| 819 | {"radeon_ring_gfx", radeon_debugfs_ring_info, 0, &radeon_gfx_index}, | 821 | {"radeon_ring_gfx", radeon_debugfs_ring_info, 0, &radeon_gfx_index}, |
| @@ -822,6 +824,8 @@ static struct drm_info_list radeon_debugfs_ring_info_list[] = { | |||
| 822 | {"radeon_ring_dma1", radeon_debugfs_ring_info, 0, &radeon_dma1_index}, | 824 | {"radeon_ring_dma1", radeon_debugfs_ring_info, 0, &radeon_dma1_index}, |
| 823 | {"radeon_ring_dma2", radeon_debugfs_ring_info, 0, &radeon_dma2_index}, | 825 | {"radeon_ring_dma2", radeon_debugfs_ring_info, 0, &radeon_dma2_index}, |
| 824 | {"radeon_ring_uvd", radeon_debugfs_ring_info, 0, &r600_uvd_index}, | 826 | {"radeon_ring_uvd", radeon_debugfs_ring_info, 0, &r600_uvd_index}, |
| 827 | {"radeon_ring_vce1", radeon_debugfs_ring_info, 0, &si_vce1_index}, | ||
| 828 | {"radeon_ring_vce2", radeon_debugfs_ring_info, 0, &si_vce2_index}, | ||
| 825 | }; | 829 | }; |
| 826 | 830 | ||
| 827 | static int radeon_debugfs_sa_info(struct seq_file *m, void *data) | 831 | static int radeon_debugfs_sa_info(struct seq_file *m, void *data) |
diff --git a/drivers/gpu/drm/radeon/radeon_test.c b/drivers/gpu/drm/radeon/radeon_test.c index 12e8099a0823..3a13e0d1055c 100644 --- a/drivers/gpu/drm/radeon/radeon_test.c +++ b/drivers/gpu/drm/radeon/radeon_test.c | |||
| @@ -257,20 +257,36 @@ static int radeon_test_create_and_emit_fence(struct radeon_device *rdev, | |||
| 257 | struct radeon_ring *ring, | 257 | struct radeon_ring *ring, |
| 258 | struct radeon_fence **fence) | 258 | struct radeon_fence **fence) |
| 259 | { | 259 | { |
| 260 | uint32_t handle = ring->idx ^ 0xdeafbeef; | ||
| 260 | int r; | 261 | int r; |
| 261 | 262 | ||
| 262 | if (ring->idx == R600_RING_TYPE_UVD_INDEX) { | 263 | if (ring->idx == R600_RING_TYPE_UVD_INDEX) { |
| 263 | r = radeon_uvd_get_create_msg(rdev, ring->idx, 1, NULL); | 264 | r = radeon_uvd_get_create_msg(rdev, ring->idx, handle, NULL); |
| 264 | if (r) { | 265 | if (r) { |
| 265 | DRM_ERROR("Failed to get dummy create msg\n"); | 266 | DRM_ERROR("Failed to get dummy create msg\n"); |
| 266 | return r; | 267 | return r; |
| 267 | } | 268 | } |
| 268 | 269 | ||
| 269 | r = radeon_uvd_get_destroy_msg(rdev, ring->idx, 1, fence); | 270 | r = radeon_uvd_get_destroy_msg(rdev, ring->idx, handle, fence); |
| 270 | if (r) { | 271 | if (r) { |
| 271 | DRM_ERROR("Failed to get dummy destroy msg\n"); | 272 | DRM_ERROR("Failed to get dummy destroy msg\n"); |
| 272 | return r; | 273 | return r; |
| 273 | } | 274 | } |
| 275 | |||
| 276 | } else if (ring->idx == TN_RING_TYPE_VCE1_INDEX || | ||
| 277 | ring->idx == TN_RING_TYPE_VCE2_INDEX) { | ||
| 278 | r = radeon_vce_get_create_msg(rdev, ring->idx, handle, NULL); | ||
| 279 | if (r) { | ||
| 280 | DRM_ERROR("Failed to get dummy create msg\n"); | ||
| 281 | return r; | ||
| 282 | } | ||
| 283 | |||
| 284 | r = radeon_vce_get_destroy_msg(rdev, ring->idx, handle, fence); | ||
| 285 | if (r) { | ||
| 286 | DRM_ERROR("Failed to get dummy destroy msg\n"); | ||
| 287 | return r; | ||
| 288 | } | ||
| 289 | |||
| 274 | } else { | 290 | } else { |
| 275 | r = radeon_ring_lock(rdev, ring, 64); | 291 | r = radeon_ring_lock(rdev, ring, 64); |
| 276 | if (r) { | 292 | if (r) { |
| @@ -486,6 +502,16 @@ out_cleanup: | |||
| 486 | printk(KERN_WARNING "Error while testing ring sync (%d).\n", r); | 502 | printk(KERN_WARNING "Error while testing ring sync (%d).\n", r); |
| 487 | } | 503 | } |
| 488 | 504 | ||
| 505 | static bool radeon_test_sync_possible(struct radeon_ring *ringA, | ||
| 506 | struct radeon_ring *ringB) | ||
| 507 | { | ||
| 508 | if (ringA->idx == TN_RING_TYPE_VCE2_INDEX && | ||
| 509 | ringB->idx == TN_RING_TYPE_VCE1_INDEX) | ||
| 510 | return false; | ||
| 511 | |||
| 512 | return true; | ||
| 513 | } | ||
| 514 | |||
| 489 | void radeon_test_syncing(struct radeon_device *rdev) | 515 | void radeon_test_syncing(struct radeon_device *rdev) |
| 490 | { | 516 | { |
| 491 | int i, j, k; | 517 | int i, j, k; |
| @@ -500,6 +526,9 @@ void radeon_test_syncing(struct radeon_device *rdev) | |||
| 500 | if (!ringB->ready) | 526 | if (!ringB->ready) |
| 501 | continue; | 527 | continue; |
| 502 | 528 | ||
| 529 | if (!radeon_test_sync_possible(ringA, ringB)) | ||
| 530 | continue; | ||
| 531 | |||
| 503 | DRM_INFO("Testing syncing between rings %d and %d...\n", i, j); | 532 | DRM_INFO("Testing syncing between rings %d and %d...\n", i, j); |
| 504 | radeon_test_ring_sync(rdev, ringA, ringB); | 533 | radeon_test_ring_sync(rdev, ringA, ringB); |
| 505 | 534 | ||
| @@ -511,6 +540,12 @@ void radeon_test_syncing(struct radeon_device *rdev) | |||
| 511 | if (!ringC->ready) | 540 | if (!ringC->ready) |
| 512 | continue; | 541 | continue; |
| 513 | 542 | ||
| 543 | if (!radeon_test_sync_possible(ringA, ringC)) | ||
| 544 | continue; | ||
| 545 | |||
| 546 | if (!radeon_test_sync_possible(ringB, ringC)) | ||
| 547 | continue; | ||
| 548 | |||
| 514 | DRM_INFO("Testing syncing between rings %d, %d and %d...\n", i, j, k); | 549 | DRM_INFO("Testing syncing between rings %d, %d and %d...\n", i, j, k); |
| 515 | radeon_test_ring_sync2(rdev, ringA, ringB, ringC); | 550 | radeon_test_ring_sync2(rdev, ringA, ringB, ringC); |
| 516 | 551 | ||
diff --git a/drivers/gpu/drm/radeon/radeon_vce.c b/drivers/gpu/drm/radeon/radeon_vce.c new file mode 100644 index 000000000000..2547d8ea347a --- /dev/null +++ b/drivers/gpu/drm/radeon/radeon_vce.c | |||
| @@ -0,0 +1,588 @@ | |||
| 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 | #include <linux/module.h> | ||
| 30 | #include <drm/drmP.h> | ||
| 31 | #include <drm/drm.h> | ||
| 32 | |||
| 33 | #include "radeon.h" | ||
| 34 | #include "radeon_asic.h" | ||
| 35 | #include "sid.h" | ||
| 36 | |||
| 37 | /* Firmware Names */ | ||
| 38 | #define FIRMWARE_BONAIRE "radeon/BONAIRE_vce.bin" | ||
| 39 | |||
| 40 | MODULE_FIRMWARE(FIRMWARE_BONAIRE); | ||
| 41 | |||
| 42 | /** | ||
| 43 | * radeon_vce_init - allocate memory, load vce firmware | ||
| 44 | * | ||
| 45 | * @rdev: radeon_device pointer | ||
| 46 | * | ||
| 47 | * First step to get VCE online, allocate memory and load the firmware | ||
| 48 | */ | ||
| 49 | int radeon_vce_init(struct radeon_device *rdev) | ||
| 50 | { | ||
| 51 | unsigned long bo_size; | ||
| 52 | const char *fw_name; | ||
| 53 | int i, r; | ||
| 54 | |||
| 55 | switch (rdev->family) { | ||
| 56 | case CHIP_BONAIRE: | ||
| 57 | case CHIP_KAVERI: | ||
| 58 | case CHIP_KABINI: | ||
| 59 | fw_name = FIRMWARE_BONAIRE; | ||
| 60 | break; | ||
| 61 | |||
| 62 | default: | ||
| 63 | return -EINVAL; | ||
| 64 | } | ||
| 65 | |||
| 66 | r = request_firmware(&rdev->vce_fw, fw_name, rdev->dev); | ||
| 67 | if (r) { | ||
| 68 | dev_err(rdev->dev, "radeon_vce: Can't load firmware \"%s\"\n", | ||
| 69 | fw_name); | ||
| 70 | return r; | ||
| 71 | } | ||
| 72 | |||
| 73 | bo_size = RADEON_GPU_PAGE_ALIGN(rdev->vce_fw->size) + | ||
| 74 | RADEON_VCE_STACK_SIZE + RADEON_VCE_HEAP_SIZE; | ||
| 75 | r = radeon_bo_create(rdev, bo_size, PAGE_SIZE, true, | ||
| 76 | RADEON_GEM_DOMAIN_VRAM, NULL, &rdev->vce.vcpu_bo); | ||
| 77 | if (r) { | ||
| 78 | dev_err(rdev->dev, "(%d) failed to allocate VCE bo\n", r); | ||
| 79 | return r; | ||
| 80 | } | ||
| 81 | |||
| 82 | r = radeon_vce_resume(rdev); | ||
| 83 | if (r) | ||
| 84 | return r; | ||
| 85 | |||
| 86 | memset(rdev->vce.cpu_addr, 0, bo_size); | ||
| 87 | memcpy(rdev->vce.cpu_addr, rdev->vce_fw->data, rdev->vce_fw->size); | ||
| 88 | |||
| 89 | r = radeon_vce_suspend(rdev); | ||
| 90 | if (r) | ||
| 91 | return r; | ||
| 92 | |||
| 93 | for (i = 0; i < RADEON_MAX_VCE_HANDLES; ++i) { | ||
| 94 | atomic_set(&rdev->vce.handles[i], 0); | ||
| 95 | rdev->vce.filp[i] = NULL; | ||
| 96 | } | ||
| 97 | |||
| 98 | return 0; | ||
| 99 | } | ||
| 100 | |||
| 101 | /** | ||
| 102 | * radeon_vce_fini - free memory | ||
| 103 | * | ||
| 104 | * @rdev: radeon_device pointer | ||
| 105 | * | ||
| 106 | * Last step on VCE teardown, free firmware memory | ||
| 107 | */ | ||
| 108 | void radeon_vce_fini(struct radeon_device *rdev) | ||
| 109 | { | ||
| 110 | radeon_vce_suspend(rdev); | ||
| 111 | radeon_bo_unref(&rdev->vce.vcpu_bo); | ||
| 112 | } | ||
| 113 | |||
| 114 | /** | ||
| 115 | * radeon_vce_suspend - unpin VCE fw memory | ||
| 116 | * | ||
| 117 | * @rdev: radeon_device pointer | ||
| 118 | * | ||
| 119 | * TODO: Test VCE suspend/resume | ||
| 120 | */ | ||
| 121 | int radeon_vce_suspend(struct radeon_device *rdev) | ||
| 122 | { | ||
| 123 | int r; | ||
| 124 | |||
| 125 | if (rdev->vce.vcpu_bo == NULL) | ||
| 126 | return 0; | ||
| 127 | |||
| 128 | r = radeon_bo_reserve(rdev->vce.vcpu_bo, false); | ||
| 129 | if (!r) { | ||
| 130 | radeon_bo_kunmap(rdev->vce.vcpu_bo); | ||
| 131 | radeon_bo_unpin(rdev->vce.vcpu_bo); | ||
| 132 | radeon_bo_unreserve(rdev->vce.vcpu_bo); | ||
| 133 | } | ||
| 134 | return r; | ||
| 135 | } | ||
| 136 | |||
| 137 | /** | ||
| 138 | * radeon_vce_resume - pin VCE fw memory | ||
| 139 | * | ||
| 140 | * @rdev: radeon_device pointer | ||
| 141 | * | ||
| 142 | * TODO: Test VCE suspend/resume | ||
| 143 | */ | ||
| 144 | int radeon_vce_resume(struct radeon_device *rdev) | ||
| 145 | { | ||
| 146 | int r; | ||
| 147 | |||
| 148 | if (rdev->vce.vcpu_bo == NULL) | ||
| 149 | return -EINVAL; | ||
| 150 | |||
| 151 | r = radeon_bo_reserve(rdev->vce.vcpu_bo, false); | ||
| 152 | if (r) { | ||
| 153 | radeon_bo_unref(&rdev->vce.vcpu_bo); | ||
| 154 | dev_err(rdev->dev, "(%d) failed to reserve VCE bo\n", r); | ||
| 155 | return r; | ||
| 156 | } | ||
| 157 | |||
| 158 | r = radeon_bo_pin(rdev->vce.vcpu_bo, RADEON_GEM_DOMAIN_VRAM, | ||
| 159 | &rdev->vce.gpu_addr); | ||
| 160 | if (r) { | ||
| 161 | radeon_bo_unreserve(rdev->vce.vcpu_bo); | ||
| 162 | radeon_bo_unref(&rdev->vce.vcpu_bo); | ||
| 163 | dev_err(rdev->dev, "(%d) VCE bo pin failed\n", r); | ||
| 164 | return r; | ||
| 165 | } | ||
| 166 | |||
| 167 | r = radeon_bo_kmap(rdev->vce.vcpu_bo, &rdev->vce.cpu_addr); | ||
| 168 | if (r) { | ||
| 169 | dev_err(rdev->dev, "(%d) VCE map failed\n", r); | ||
| 170 | return r; | ||
| 171 | } | ||
| 172 | |||
| 173 | radeon_bo_unreserve(rdev->vce.vcpu_bo); | ||
| 174 | |||
| 175 | return 0; | ||
| 176 | } | ||
| 177 | |||
| 178 | /** | ||
| 179 | * radeon_vce_free_handles - free still open VCE handles | ||
| 180 | * | ||
| 181 | * @rdev: radeon_device pointer | ||
| 182 | * @filp: drm file pointer | ||
| 183 | * | ||
| 184 | * Close all VCE handles still open by this file pointer | ||
| 185 | */ | ||
| 186 | void radeon_vce_free_handles(struct radeon_device *rdev, struct drm_file *filp) | ||
| 187 | { | ||
| 188 | int i, r; | ||
| 189 | for (i = 0; i < RADEON_MAX_VCE_HANDLES; ++i) { | ||
| 190 | uint32_t handle = atomic_read(&rdev->vce.handles[i]); | ||
| 191 | if (!handle || rdev->vce.filp[i] != filp) | ||
| 192 | continue; | ||
| 193 | |||
| 194 | r = radeon_vce_get_destroy_msg(rdev, TN_RING_TYPE_VCE1_INDEX, | ||
| 195 | handle, NULL); | ||
| 196 | if (r) | ||
| 197 | DRM_ERROR("Error destroying VCE handle (%d)!\n", r); | ||
| 198 | |||
| 199 | rdev->vce.filp[i] = NULL; | ||
| 200 | atomic_set(&rdev->vce.handles[i], 0); | ||
| 201 | } | ||
| 202 | } | ||
| 203 | |||
| 204 | /** | ||
| 205 | * radeon_vce_get_create_msg - generate a VCE create msg | ||
| 206 | * | ||
| 207 | * @rdev: radeon_device pointer | ||
| 208 | * @ring: ring we should submit the msg to | ||
| 209 | * @handle: VCE session handle to use | ||
| 210 | * @fence: optional fence to return | ||
| 211 | * | ||
| 212 | * Open up a stream for HW test | ||
| 213 | */ | ||
| 214 | int radeon_vce_get_create_msg(struct radeon_device *rdev, int ring, | ||
| 215 | uint32_t handle, struct radeon_fence **fence) | ||
| 216 | { | ||
| 217 | const unsigned ib_size_dw = 1024; | ||
| 218 | struct radeon_ib ib; | ||
| 219 | uint64_t dummy; | ||
| 220 | int i, r; | ||
| 221 | |||
| 222 | r = radeon_ib_get(rdev, ring, &ib, NULL, ib_size_dw * 4); | ||
| 223 | if (r) { | ||
| 224 | DRM_ERROR("radeon: failed to get ib (%d).\n", r); | ||
| 225 | return r; | ||
| 226 | } | ||
| 227 | |||
| 228 | dummy = ib.gpu_addr + 1024; | ||
| 229 | |||
| 230 | /* stitch together an VCE create msg */ | ||
| 231 | ib.length_dw = 0; | ||
| 232 | ib.ptr[ib.length_dw++] = 0x0000000c; /* len */ | ||
| 233 | ib.ptr[ib.length_dw++] = 0x00000001; /* session cmd */ | ||
| 234 | ib.ptr[ib.length_dw++] = handle; | ||
| 235 | |||
| 236 | ib.ptr[ib.length_dw++] = 0x00000030; /* len */ | ||
| 237 | ib.ptr[ib.length_dw++] = 0x01000001; /* create cmd */ | ||
| 238 | ib.ptr[ib.length_dw++] = 0x00000000; | ||
| 239 | ib.ptr[ib.length_dw++] = 0x00000042; | ||
| 240 | ib.ptr[ib.length_dw++] = 0x0000000a; | ||
| 241 | ib.ptr[ib.length_dw++] = 0x00000001; | ||
| 242 | ib.ptr[ib.length_dw++] = 0x00000080; | ||
| 243 | ib.ptr[ib.length_dw++] = 0x00000060; | ||
| 244 | ib.ptr[ib.length_dw++] = 0x00000100; | ||
| 245 | ib.ptr[ib.length_dw++] = 0x00000100; | ||
| 246 | ib.ptr[ib.length_dw++] = 0x0000000c; | ||
| 247 | ib.ptr[ib.length_dw++] = 0x00000000; | ||
| 248 | |||
| 249 | ib.ptr[ib.length_dw++] = 0x00000014; /* len */ | ||
| 250 | ib.ptr[ib.length_dw++] = 0x05000005; /* feedback buffer */ | ||
| 251 | ib.ptr[ib.length_dw++] = upper_32_bits(dummy); | ||
| 252 | ib.ptr[ib.length_dw++] = dummy; | ||
| 253 | ib.ptr[ib.length_dw++] = 0x00000001; | ||
| 254 | |||
| 255 | for (i = ib.length_dw; i < ib_size_dw; ++i) | ||
| 256 | ib.ptr[i] = 0x0; | ||
| 257 | |||
| 258 | r = radeon_ib_schedule(rdev, &ib, NULL); | ||
| 259 | if (r) { | ||
| 260 | DRM_ERROR("radeon: failed to schedule ib (%d).\n", r); | ||
| 261 | } | ||
| 262 | |||
| 263 | if (fence) | ||
| 264 | *fence = radeon_fence_ref(ib.fence); | ||
| 265 | |||
| 266 | radeon_ib_free(rdev, &ib); | ||
| 267 | |||
| 268 | return r; | ||
| 269 | } | ||
| 270 | |||
| 271 | /** | ||
| 272 | * radeon_vce_get_destroy_msg - generate a VCE destroy msg | ||
| 273 | * | ||
| 274 | * @rdev: radeon_device pointer | ||
| 275 | * @ring: ring we should submit the msg to | ||
| 276 | * @handle: VCE session handle to use | ||
| 277 | * @fence: optional fence to return | ||
| 278 | * | ||
| 279 | * Close up a stream for HW test or if userspace failed to do so | ||
| 280 | */ | ||
| 281 | int radeon_vce_get_destroy_msg(struct radeon_device *rdev, int ring, | ||
| 282 | uint32_t handle, struct radeon_fence **fence) | ||
| 283 | { | ||
| 284 | const unsigned ib_size_dw = 1024; | ||
| 285 | struct radeon_ib ib; | ||
| 286 | uint64_t dummy; | ||
| 287 | int i, r; | ||
| 288 | |||
| 289 | r = radeon_ib_get(rdev, ring, &ib, NULL, ib_size_dw * 4); | ||
| 290 | if (r) { | ||
| 291 | DRM_ERROR("radeon: failed to get ib (%d).\n", r); | ||
| 292 | return r; | ||
| 293 | } | ||
| 294 | |||
| 295 | dummy = ib.gpu_addr + 1024; | ||
| 296 | |||
| 297 | /* stitch together an VCE destroy msg */ | ||
| 298 | ib.length_dw = 0; | ||
| 299 | ib.ptr[ib.length_dw++] = 0x0000000c; /* len */ | ||
| 300 | ib.ptr[ib.length_dw++] = 0x00000001; /* session cmd */ | ||
| 301 | ib.ptr[ib.length_dw++] = handle; | ||
| 302 | |||
| 303 | ib.ptr[ib.length_dw++] = 0x00000014; /* len */ | ||
| 304 | ib.ptr[ib.length_dw++] = 0x05000005; /* feedback buffer */ | ||
| 305 | ib.ptr[ib.length_dw++] = upper_32_bits(dummy); | ||
| 306 | ib.ptr[ib.length_dw++] = dummy; | ||
| 307 | ib.ptr[ib.length_dw++] = 0x00000001; | ||
| 308 | |||
| 309 | ib.ptr[ib.length_dw++] = 0x00000008; /* len */ | ||
| 310 | ib.ptr[ib.length_dw++] = 0x02000001; /* destroy cmd */ | ||
| 311 | |||
| 312 | for (i = ib.length_dw; i < ib_size_dw; ++i) | ||
| 313 | ib.ptr[i] = 0x0; | ||
| 314 | |||
| 315 | r = radeon_ib_schedule(rdev, &ib, NULL); | ||
| 316 | if (r) { | ||
| 317 | DRM_ERROR("radeon: failed to schedule ib (%d).\n", r); | ||
| 318 | } | ||
| 319 | |||
| 320 | if (fence) | ||
| 321 | *fence = radeon_fence_ref(ib.fence); | ||
| 322 | |||
| 323 | radeon_ib_free(rdev, &ib); | ||
| 324 | |||
| 325 | return r; | ||
| 326 | } | ||
| 327 | |||
| 328 | /** | ||
| 329 | * radeon_vce_cs_reloc - command submission relocation | ||
| 330 | * | ||
| 331 | * @p: parser context | ||
| 332 | * @lo: address of lower dword | ||
| 333 | * @hi: address of higher dword | ||
| 334 | * | ||
| 335 | * Patch relocation inside command stream with real buffer address | ||
| 336 | */ | ||
| 337 | int radeon_vce_cs_reloc(struct radeon_cs_parser *p, int lo, int hi) | ||
| 338 | { | ||
| 339 | struct radeon_cs_chunk *relocs_chunk; | ||
| 340 | uint64_t offset; | ||
| 341 | unsigned idx; | ||
| 342 | |||
| 343 | relocs_chunk = &p->chunks[p->chunk_relocs_idx]; | ||
| 344 | offset = radeon_get_ib_value(p, lo); | ||
| 345 | idx = radeon_get_ib_value(p, hi); | ||
| 346 | |||
| 347 | if (idx >= relocs_chunk->length_dw) { | ||
| 348 | DRM_ERROR("Relocs at %d after relocations chunk end %d !\n", | ||
| 349 | idx, relocs_chunk->length_dw); | ||
| 350 | return -EINVAL; | ||
| 351 | } | ||
| 352 | |||
| 353 | offset += p->relocs_ptr[(idx / 4)]->lobj.gpu_offset; | ||
| 354 | |||
| 355 | p->ib.ptr[lo] = offset & 0xFFFFFFFF; | ||
| 356 | p->ib.ptr[hi] = offset >> 32; | ||
| 357 | |||
| 358 | return 0; | ||
| 359 | } | ||
| 360 | |||
| 361 | /** | ||
| 362 | * radeon_vce_cs_parse - parse and validate the command stream | ||
| 363 | * | ||
| 364 | * @p: parser context | ||
| 365 | * | ||
| 366 | */ | ||
| 367 | int radeon_vce_cs_parse(struct radeon_cs_parser *p) | ||
| 368 | { | ||
| 369 | uint32_t handle = 0; | ||
| 370 | bool destroy = false; | ||
| 371 | int i, r; | ||
| 372 | |||
| 373 | while (p->idx < p->chunks[p->chunk_ib_idx].length_dw) { | ||
| 374 | uint32_t len = radeon_get_ib_value(p, p->idx); | ||
| 375 | uint32_t cmd = radeon_get_ib_value(p, p->idx + 1); | ||
| 376 | |||
| 377 | if ((len < 8) || (len & 3)) { | ||
| 378 | DRM_ERROR("invalid VCE command length (%d)!\n", len); | ||
| 379 | return -EINVAL; | ||
| 380 | } | ||
| 381 | |||
| 382 | switch (cmd) { | ||
| 383 | case 0x00000001: // session | ||
| 384 | handle = radeon_get_ib_value(p, p->idx + 2); | ||
| 385 | break; | ||
| 386 | |||
| 387 | case 0x00000002: // task info | ||
| 388 | case 0x01000001: // create | ||
| 389 | case 0x04000001: // config extension | ||
| 390 | case 0x04000002: // pic control | ||
| 391 | case 0x04000005: // rate control | ||
| 392 | case 0x04000007: // motion estimation | ||
| 393 | case 0x04000008: // rdo | ||
| 394 | break; | ||
| 395 | |||
| 396 | case 0x03000001: // encode | ||
| 397 | r = radeon_vce_cs_reloc(p, p->idx + 10, p->idx + 9); | ||
| 398 | if (r) | ||
| 399 | return r; | ||
| 400 | |||
| 401 | r = radeon_vce_cs_reloc(p, p->idx + 12, p->idx + 11); | ||
| 402 | if (r) | ||
| 403 | return r; | ||
| 404 | break; | ||
| 405 | |||
| 406 | case 0x02000001: // destroy | ||
| 407 | destroy = true; | ||
| 408 | break; | ||
| 409 | |||
| 410 | case 0x05000001: // context buffer | ||
| 411 | case 0x05000004: // video bitstream buffer | ||
| 412 | case 0x05000005: // feedback buffer | ||
| 413 | r = radeon_vce_cs_reloc(p, p->idx + 3, p->idx + 2); | ||
| 414 | if (r) | ||
| 415 | return r; | ||
| 416 | break; | ||
| 417 | |||
| 418 | default: | ||
| 419 | DRM_ERROR("invalid VCE command (0x%x)!\n", cmd); | ||
| 420 | return -EINVAL; | ||
| 421 | } | ||
| 422 | |||
| 423 | p->idx += len / 4; | ||
| 424 | } | ||
| 425 | |||
| 426 | if (destroy) { | ||
| 427 | /* IB contains a destroy msg, free the handle */ | ||
| 428 | for (i = 0; i < RADEON_MAX_VCE_HANDLES; ++i) | ||
| 429 | atomic_cmpxchg(&p->rdev->vce.handles[i], handle, 0); | ||
| 430 | |||
| 431 | return 0; | ||
| 432 | } | ||
| 433 | |||
| 434 | /* create or encode, validate the handle */ | ||
| 435 | for (i = 0; i < RADEON_MAX_VCE_HANDLES; ++i) { | ||
| 436 | if (atomic_read(&p->rdev->vce.handles[i]) == handle) | ||
| 437 | return 0; | ||
| 438 | } | ||
| 439 | |||
| 440 | /* handle not found try to alloc a new one */ | ||
| 441 | for (i = 0; i < RADEON_MAX_VCE_HANDLES; ++i) { | ||
| 442 | if (!atomic_cmpxchg(&p->rdev->vce.handles[i], 0, handle)) { | ||
| 443 | p->rdev->vce.filp[i] = p->filp; | ||
| 444 | return 0; | ||
| 445 | } | ||
| 446 | } | ||
| 447 | |||
| 448 | DRM_ERROR("No more free VCE handles!\n"); | ||
| 449 | return -EINVAL; | ||
| 450 | } | ||
| 451 | |||
| 452 | /** | ||
| 453 | * radeon_vce_semaphore_emit - emit a semaphore command | ||
| 454 | * | ||
| 455 | * @rdev: radeon_device pointer | ||
| 456 | * @ring: engine to use | ||
| 457 | * @semaphore: address of semaphore | ||
| 458 | * @emit_wait: true=emit wait, false=emit signal | ||
| 459 | * | ||
| 460 | */ | ||
| 461 | bool radeon_vce_semaphore_emit(struct radeon_device *rdev, | ||
| 462 | struct radeon_ring *ring, | ||
| 463 | struct radeon_semaphore *semaphore, | ||
| 464 | bool emit_wait) | ||
| 465 | { | ||
| 466 | uint64_t addr = semaphore->gpu_addr; | ||
| 467 | |||
| 468 | radeon_ring_write(ring, VCE_CMD_SEMAPHORE); | ||
| 469 | radeon_ring_write(ring, (addr >> 3) & 0x000FFFFF); | ||
| 470 | radeon_ring_write(ring, (addr >> 23) & 0x000FFFFF); | ||
| 471 | radeon_ring_write(ring, 0x01003000 | (emit_wait ? 1 : 0)); | ||
| 472 | if (!emit_wait) | ||
| 473 | radeon_ring_write(ring, VCE_CMD_END); | ||
| 474 | |||
| 475 | return true; | ||
| 476 | } | ||
| 477 | |||
| 478 | /** | ||
| 479 | * radeon_vce_ib_execute - execute indirect buffer | ||
| 480 | * | ||
| 481 | * @rdev: radeon_device pointer | ||
| 482 | * @ib: the IB to execute | ||
| 483 | * | ||
| 484 | */ | ||
| 485 | void radeon_vce_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib) | ||
| 486 | { | ||
| 487 | struct radeon_ring *ring = &rdev->ring[ib->ring]; | ||
| 488 | radeon_ring_write(ring, VCE_CMD_IB); | ||
| 489 | radeon_ring_write(ring, ib->gpu_addr); | ||
| 490 | radeon_ring_write(ring, upper_32_bits(ib->gpu_addr)); | ||
| 491 | radeon_ring_write(ring, ib->length_dw); | ||
| 492 | } | ||
| 493 | |||
| 494 | /** | ||
| 495 | * radeon_vce_fence_emit - add a fence command to the ring | ||
| 496 | * | ||
| 497 | * @rdev: radeon_device pointer | ||
| 498 | * @fence: the fence | ||
| 499 | * | ||
| 500 | */ | ||
| 501 | void radeon_vce_fence_emit(struct radeon_device *rdev, | ||
| 502 | struct radeon_fence *fence) | ||
| 503 | { | ||
| 504 | struct radeon_ring *ring = &rdev->ring[fence->ring]; | ||
| 505 | uint32_t addr = rdev->fence_drv[fence->ring].gpu_addr; | ||
| 506 | |||
| 507 | radeon_ring_write(ring, VCE_CMD_FENCE); | ||
| 508 | radeon_ring_write(ring, addr); | ||
| 509 | radeon_ring_write(ring, upper_32_bits(addr)); | ||
| 510 | radeon_ring_write(ring, fence->seq); | ||
| 511 | radeon_ring_write(ring, VCE_CMD_TRAP); | ||
| 512 | radeon_ring_write(ring, VCE_CMD_END); | ||
| 513 | } | ||
| 514 | |||
| 515 | /** | ||
| 516 | * radeon_vce_ring_test - test if VCE ring is working | ||
| 517 | * | ||
| 518 | * @rdev: radeon_device pointer | ||
| 519 | * @ring: the engine to test on | ||
| 520 | * | ||
| 521 | */ | ||
| 522 | int radeon_vce_ring_test(struct radeon_device *rdev, struct radeon_ring *ring) | ||
| 523 | { | ||
| 524 | uint32_t rptr = vce_v1_0_get_rptr(rdev, ring); | ||
| 525 | unsigned i; | ||
| 526 | int r; | ||
| 527 | |||
| 528 | r = radeon_ring_lock(rdev, ring, 16); | ||
| 529 | if (r) { | ||
| 530 | DRM_ERROR("radeon: vce failed to lock ring %d (%d).\n", | ||
| 531 | ring->idx, r); | ||
| 532 | return r; | ||
| 533 | } | ||
| 534 | radeon_ring_write(ring, VCE_CMD_END); | ||
| 535 | radeon_ring_unlock_commit(rdev, ring); | ||
| 536 | |||
| 537 | for (i = 0; i < rdev->usec_timeout; i++) { | ||
| 538 | if (vce_v1_0_get_rptr(rdev, ring) != rptr) | ||
| 539 | break; | ||
| 540 | DRM_UDELAY(1); | ||
| 541 | } | ||
| 542 | |||
| 543 | if (i < rdev->usec_timeout) { | ||
| 544 | DRM_INFO("ring test on %d succeeded in %d usecs\n", | ||
| 545 | ring->idx, i); | ||
| 546 | } else { | ||
| 547 | DRM_ERROR("radeon: ring %d test failed\n", | ||
| 548 | ring->idx); | ||
| 549 | r = -ETIMEDOUT; | ||
| 550 | } | ||
| 551 | |||
| 552 | return r; | ||
| 553 | } | ||
| 554 | |||
| 555 | /** | ||
| 556 | * radeon_vce_ib_test - test if VCE IBs are working | ||
| 557 | * | ||
| 558 | * @rdev: radeon_device pointer | ||
| 559 | * @ring: the engine to test on | ||
| 560 | * | ||
| 561 | */ | ||
| 562 | int radeon_vce_ib_test(struct radeon_device *rdev, struct radeon_ring *ring) | ||
| 563 | { | ||
| 564 | struct radeon_fence *fence = NULL; | ||
| 565 | int r; | ||
| 566 | |||
| 567 | r = radeon_vce_get_create_msg(rdev, ring->idx, 1, NULL); | ||
| 568 | if (r) { | ||
| 569 | DRM_ERROR("radeon: failed to get create msg (%d).\n", r); | ||
| 570 | goto error; | ||
| 571 | } | ||
| 572 | |||
| 573 | r = radeon_vce_get_destroy_msg(rdev, ring->idx, 1, &fence); | ||
| 574 | if (r) { | ||
| 575 | DRM_ERROR("radeon: failed to get destroy ib (%d).\n", r); | ||
| 576 | goto error; | ||
| 577 | } | ||
| 578 | |||
| 579 | r = radeon_fence_wait(fence, false); | ||
| 580 | if (r) { | ||
| 581 | DRM_ERROR("radeon: fence wait failed (%d).\n", r); | ||
| 582 | } else { | ||
| 583 | DRM_INFO("ib test on ring %d succeeded\n", ring->idx); | ||
| 584 | } | ||
| 585 | error: | ||
| 586 | radeon_fence_unref(&fence); | ||
| 587 | return r; | ||
| 588 | } | ||
diff --git a/drivers/gpu/drm/radeon/sid.h b/drivers/gpu/drm/radeon/sid.h index 9239a6d29128..683532f84931 100644 --- a/drivers/gpu/drm/radeon/sid.h +++ b/drivers/gpu/drm/radeon/sid.h | |||
| @@ -1798,4 +1798,51 @@ | |||
| 1798 | #define DMA_PACKET_CONSTANT_FILL 0xd | 1798 | #define DMA_PACKET_CONSTANT_FILL 0xd |
| 1799 | #define DMA_PACKET_NOP 0xf | 1799 | #define DMA_PACKET_NOP 0xf |
| 1800 | 1800 | ||
| 1801 | #define VCE_STATUS 0x20004 | ||
| 1802 | #define VCE_VCPU_CNTL 0x20014 | ||
| 1803 | #define VCE_CLK_EN (1 << 0) | ||
| 1804 | #define VCE_VCPU_CACHE_OFFSET0 0x20024 | ||
| 1805 | #define VCE_VCPU_CACHE_SIZE0 0x20028 | ||
| 1806 | #define VCE_VCPU_CACHE_OFFSET1 0x2002c | ||
| 1807 | #define VCE_VCPU_CACHE_SIZE1 0x20030 | ||
| 1808 | #define VCE_VCPU_CACHE_OFFSET2 0x20034 | ||
| 1809 | #define VCE_VCPU_CACHE_SIZE2 0x20038 | ||
| 1810 | #define VCE_SOFT_RESET 0x20120 | ||
| 1811 | #define VCE_ECPU_SOFT_RESET (1 << 0) | ||
| 1812 | #define VCE_FME_SOFT_RESET (1 << 2) | ||
| 1813 | #define VCE_RB_BASE_LO2 0x2016c | ||
| 1814 | #define VCE_RB_BASE_HI2 0x20170 | ||
| 1815 | #define VCE_RB_SIZE2 0x20174 | ||
| 1816 | #define VCE_RB_RPTR2 0x20178 | ||
| 1817 | #define VCE_RB_WPTR2 0x2017c | ||
| 1818 | #define VCE_RB_BASE_LO 0x20180 | ||
| 1819 | #define VCE_RB_BASE_HI 0x20184 | ||
| 1820 | #define VCE_RB_SIZE 0x20188 | ||
| 1821 | #define VCE_RB_RPTR 0x2018c | ||
| 1822 | #define VCE_RB_WPTR 0x20190 | ||
| 1823 | #define VCE_CLOCK_GATING_A 0x202f8 | ||
| 1824 | #define VCE_CLOCK_GATING_B 0x202fc | ||
| 1825 | #define VCE_UENC_CLOCK_GATING 0x205bc | ||
| 1826 | #define VCE_UENC_REG_CLOCK_GATING 0x205c0 | ||
| 1827 | #define VCE_FW_REG_STATUS 0x20e10 | ||
| 1828 | # define VCE_FW_REG_STATUS_BUSY (1 << 0) | ||
| 1829 | # define VCE_FW_REG_STATUS_PASS (1 << 3) | ||
| 1830 | # define VCE_FW_REG_STATUS_DONE (1 << 11) | ||
| 1831 | #define VCE_LMI_FW_START_KEYSEL 0x20e18 | ||
| 1832 | #define VCE_LMI_FW_PERIODIC_CTRL 0x20e20 | ||
| 1833 | #define VCE_LMI_CTRL2 0x20e74 | ||
| 1834 | #define VCE_LMI_CTRL 0x20e98 | ||
| 1835 | #define VCE_LMI_VM_CTRL 0x20ea0 | ||
| 1836 | #define VCE_LMI_SWAP_CNTL 0x20eb4 | ||
| 1837 | #define VCE_LMI_SWAP_CNTL1 0x20eb8 | ||
| 1838 | #define VCE_LMI_CACHE_CTRL 0x20ef4 | ||
| 1839 | |||
| 1840 | #define VCE_CMD_NO_OP 0x00000000 | ||
| 1841 | #define VCE_CMD_END 0x00000001 | ||
| 1842 | #define VCE_CMD_IB 0x00000002 | ||
| 1843 | #define VCE_CMD_FENCE 0x00000003 | ||
| 1844 | #define VCE_CMD_TRAP 0x00000004 | ||
| 1845 | #define VCE_CMD_IB_AUTO 0x00000005 | ||
| 1846 | #define VCE_CMD_SEMAPHORE 0x00000006 | ||
| 1847 | |||
| 1801 | #endif | 1848 | #endif |
diff --git a/drivers/gpu/drm/radeon/vce_v1_0.c b/drivers/gpu/drm/radeon/vce_v1_0.c new file mode 100644 index 000000000000..e0c3534356a1 --- /dev/null +++ b/drivers/gpu/drm/radeon/vce_v1_0.c | |||
| @@ -0,0 +1,187 @@ | |||
| 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 | #include <drm/drmP.h> | ||
| 30 | #include "radeon.h" | ||
| 31 | #include "radeon_asic.h" | ||
| 32 | #include "sid.h" | ||
| 33 | |||
| 34 | /** | ||
| 35 | * vce_v1_0_get_rptr - get read pointer | ||
| 36 | * | ||
| 37 | * @rdev: radeon_device pointer | ||
| 38 | * @ring: radeon_ring pointer | ||
| 39 | * | ||
| 40 | * Returns the current hardware read pointer | ||
| 41 | */ | ||
| 42 | uint32_t vce_v1_0_get_rptr(struct radeon_device *rdev, | ||
| 43 | struct radeon_ring *ring) | ||
| 44 | { | ||
| 45 | if (ring->idx == TN_RING_TYPE_VCE1_INDEX) | ||
| 46 | return RREG32(VCE_RB_RPTR); | ||
| 47 | else | ||
| 48 | return RREG32(VCE_RB_RPTR2); | ||
| 49 | } | ||
| 50 | |||
| 51 | /** | ||
| 52 | * vce_v1_0_get_wptr - get write pointer | ||
| 53 | * | ||
| 54 | * @rdev: radeon_device pointer | ||
| 55 | * @ring: radeon_ring pointer | ||
| 56 | * | ||
| 57 | * Returns the current hardware write pointer | ||
| 58 | */ | ||
| 59 | uint32_t vce_v1_0_get_wptr(struct radeon_device *rdev, | ||
| 60 | struct radeon_ring *ring) | ||
| 61 | { | ||
| 62 | if (ring->idx == TN_RING_TYPE_VCE1_INDEX) | ||
| 63 | return RREG32(VCE_RB_WPTR); | ||
| 64 | else | ||
| 65 | return RREG32(VCE_RB_WPTR2); | ||
| 66 | } | ||
| 67 | |||
| 68 | /** | ||
| 69 | * vce_v1_0_set_wptr - set write pointer | ||
| 70 | * | ||
| 71 | * @rdev: radeon_device pointer | ||
| 72 | * @ring: radeon_ring pointer | ||
| 73 | * | ||
| 74 | * Commits the write pointer to the hardware | ||
| 75 | */ | ||
| 76 | void vce_v1_0_set_wptr(struct radeon_device *rdev, | ||
| 77 | struct radeon_ring *ring) | ||
| 78 | { | ||
| 79 | if (ring->idx == TN_RING_TYPE_VCE1_INDEX) | ||
| 80 | WREG32(VCE_RB_WPTR, ring->wptr); | ||
| 81 | else | ||
| 82 | WREG32(VCE_RB_WPTR2, ring->wptr); | ||
| 83 | } | ||
| 84 | |||
| 85 | /** | ||
| 86 | * vce_v1_0_start - start VCE block | ||
| 87 | * | ||
| 88 | * @rdev: radeon_device pointer | ||
| 89 | * | ||
| 90 | * Setup and start the VCE block | ||
| 91 | */ | ||
| 92 | int vce_v1_0_start(struct radeon_device *rdev) | ||
| 93 | { | ||
| 94 | struct radeon_ring *ring; | ||
| 95 | int i, j, r; | ||
| 96 | |||
| 97 | /* set BUSY flag */ | ||
| 98 | WREG32_P(VCE_STATUS, 1, ~1); | ||
| 99 | |||
| 100 | ring = &rdev->ring[TN_RING_TYPE_VCE1_INDEX]; | ||
| 101 | WREG32(VCE_RB_RPTR, ring->rptr); | ||
| 102 | WREG32(VCE_RB_WPTR, ring->wptr); | ||
| 103 | WREG32(VCE_RB_BASE_LO, ring->gpu_addr); | ||
| 104 | WREG32(VCE_RB_BASE_HI, upper_32_bits(ring->gpu_addr)); | ||
| 105 | WREG32(VCE_RB_SIZE, ring->ring_size / 4); | ||
| 106 | |||
| 107 | ring = &rdev->ring[TN_RING_TYPE_VCE2_INDEX]; | ||
| 108 | WREG32(VCE_RB_RPTR2, ring->rptr); | ||
| 109 | WREG32(VCE_RB_WPTR2, ring->wptr); | ||
| 110 | WREG32(VCE_RB_BASE_LO2, ring->gpu_addr); | ||
| 111 | WREG32(VCE_RB_BASE_HI2, upper_32_bits(ring->gpu_addr)); | ||
| 112 | WREG32(VCE_RB_SIZE2, ring->ring_size / 4); | ||
| 113 | |||
| 114 | WREG32_P(VCE_VCPU_CNTL, VCE_CLK_EN, ~VCE_CLK_EN); | ||
| 115 | |||
| 116 | WREG32_P(VCE_SOFT_RESET, | ||
| 117 | VCE_ECPU_SOFT_RESET | | ||
| 118 | VCE_FME_SOFT_RESET, ~( | ||
| 119 | VCE_ECPU_SOFT_RESET | | ||
| 120 | VCE_FME_SOFT_RESET)); | ||
| 121 | |||
| 122 | mdelay(100); | ||
| 123 | |||
| 124 | WREG32_P(VCE_SOFT_RESET, 0, ~( | ||
| 125 | VCE_ECPU_SOFT_RESET | | ||
| 126 | VCE_FME_SOFT_RESET)); | ||
| 127 | |||
| 128 | for (i = 0; i < 10; ++i) { | ||
| 129 | uint32_t status; | ||
| 130 | for (j = 0; j < 100; ++j) { | ||
| 131 | status = RREG32(VCE_STATUS); | ||
| 132 | if (status & 2) | ||
| 133 | break; | ||
| 134 | mdelay(10); | ||
| 135 | } | ||
| 136 | r = 0; | ||
| 137 | if (status & 2) | ||
| 138 | break; | ||
| 139 | |||
| 140 | DRM_ERROR("VCE not responding, trying to reset the ECPU!!!\n"); | ||
| 141 | WREG32_P(VCE_SOFT_RESET, VCE_ECPU_SOFT_RESET, ~VCE_ECPU_SOFT_RESET); | ||
| 142 | mdelay(10); | ||
| 143 | WREG32_P(VCE_SOFT_RESET, 0, ~VCE_ECPU_SOFT_RESET); | ||
| 144 | mdelay(10); | ||
| 145 | r = -1; | ||
| 146 | } | ||
| 147 | |||
| 148 | /* clear BUSY flag */ | ||
| 149 | WREG32_P(VCE_STATUS, 0, ~1); | ||
| 150 | |||
| 151 | if (r) { | ||
| 152 | DRM_ERROR("VCE not responding, giving up!!!\n"); | ||
| 153 | return r; | ||
| 154 | } | ||
| 155 | |||
| 156 | return 0; | ||
| 157 | } | ||
| 158 | |||
| 159 | int vce_v1_0_init(struct radeon_device *rdev) | ||
| 160 | { | ||
| 161 | struct radeon_ring *ring; | ||
| 162 | int r; | ||
| 163 | |||
| 164 | r = vce_v1_0_start(rdev); | ||
| 165 | if (r) | ||
| 166 | return r; | ||
| 167 | |||
| 168 | ring = &rdev->ring[TN_RING_TYPE_VCE1_INDEX]; | ||
| 169 | ring->ready = true; | ||
| 170 | r = radeon_ring_test(rdev, TN_RING_TYPE_VCE1_INDEX, ring); | ||
| 171 | if (r) { | ||
| 172 | ring->ready = false; | ||
| 173 | return r; | ||
| 174 | } | ||
| 175 | |||
| 176 | ring = &rdev->ring[TN_RING_TYPE_VCE2_INDEX]; | ||
| 177 | ring->ready = true; | ||
| 178 | r = radeon_ring_test(rdev, TN_RING_TYPE_VCE2_INDEX, ring); | ||
| 179 | if (r) { | ||
| 180 | ring->ready = false; | ||
| 181 | return r; | ||
| 182 | } | ||
| 183 | |||
| 184 | DRM_INFO("VCE initialized successfully.\n"); | ||
| 185 | |||
| 186 | return 0; | ||
| 187 | } | ||
diff --git a/drivers/gpu/drm/radeon/vce_v2_0.c b/drivers/gpu/drm/radeon/vce_v2_0.c new file mode 100644 index 000000000000..4911d1b00e3b --- /dev/null +++ b/drivers/gpu/drm/radeon/vce_v2_0.c | |||
| @@ -0,0 +1,70 @@ | |||
| 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 | #include <drm/drmP.h> | ||
| 30 | #include "radeon.h" | ||
| 31 | #include "radeon_asic.h" | ||
| 32 | #include "cikd.h" | ||
| 33 | |||
| 34 | int vce_v2_0_resume(struct radeon_device *rdev) | ||
| 35 | { | ||
| 36 | uint64_t addr = rdev->vce.gpu_addr; | ||
| 37 | uint32_t size; | ||
| 38 | |||
| 39 | WREG32_P(VCE_CLOCK_GATING_A, 0, ~(1 << 16)); | ||
| 40 | WREG32_P(VCE_UENC_CLOCK_GATING, 0x1FF000, ~0xFF9FF000); | ||
| 41 | WREG32_P(VCE_UENC_REG_CLOCK_GATING, 0x3F, ~0x3F); | ||
| 42 | WREG32(VCE_CLOCK_GATING_B, 0xf7); | ||
| 43 | |||
| 44 | WREG32(VCE_LMI_CTRL, 0x00398000); | ||
| 45 | WREG32_P(VCE_LMI_CACHE_CTRL, 0x0, ~0x1); | ||
| 46 | WREG32(VCE_LMI_SWAP_CNTL, 0); | ||
| 47 | WREG32(VCE_LMI_SWAP_CNTL1, 0); | ||
| 48 | WREG32(VCE_LMI_VM_CTRL, 0); | ||
| 49 | |||
| 50 | size = RADEON_GPU_PAGE_ALIGN(rdev->vce_fw->size); | ||
| 51 | WREG32(VCE_VCPU_CACHE_OFFSET0, addr & 0x7fffffff); | ||
| 52 | WREG32(VCE_VCPU_CACHE_SIZE0, size); | ||
| 53 | |||
| 54 | addr += size; | ||
| 55 | size = RADEON_VCE_STACK_SIZE; | ||
| 56 | WREG32(VCE_VCPU_CACHE_OFFSET1, addr & 0x7fffffff); | ||
| 57 | WREG32(VCE_VCPU_CACHE_SIZE1, size); | ||
| 58 | |||
| 59 | addr += size; | ||
| 60 | size = RADEON_VCE_HEAP_SIZE; | ||
| 61 | WREG32(VCE_VCPU_CACHE_OFFSET2, addr & 0x7fffffff); | ||
| 62 | WREG32(VCE_VCPU_CACHE_SIZE2, size); | ||
| 63 | |||
| 64 | WREG32_P(VCE_LMI_CTRL2, 0x0, ~0x100); | ||
| 65 | |||
| 66 | WREG32_P(VCE_SYS_INT_EN, VCE_SYS_INT_TRAP_INTERRUPT_EN, | ||
| 67 | ~VCE_SYS_INT_TRAP_INTERRUPT_EN); | ||
| 68 | |||
| 69 | return 0; | ||
| 70 | } | ||
diff --git a/include/uapi/drm/radeon_drm.h b/include/uapi/drm/radeon_drm.h index d9ea3a73afe2..6493ca55b463 100644 --- a/include/uapi/drm/radeon_drm.h +++ b/include/uapi/drm/radeon_drm.h | |||
| @@ -919,6 +919,7 @@ struct drm_radeon_gem_va { | |||
| 919 | #define RADEON_CS_RING_COMPUTE 1 | 919 | #define RADEON_CS_RING_COMPUTE 1 |
| 920 | #define RADEON_CS_RING_DMA 2 | 920 | #define RADEON_CS_RING_DMA 2 |
| 921 | #define RADEON_CS_RING_UVD 3 | 921 | #define RADEON_CS_RING_UVD 3 |
| 922 | #define RADEON_CS_RING_VCE 4 | ||
| 922 | /* The third dword of RADEON_CHUNK_ID_FLAGS is a sint32 that sets the priority */ | 923 | /* The third dword of RADEON_CHUNK_ID_FLAGS is a sint32 that sets the priority */ |
| 923 | /* 0 = normal, + = higher priority, - = lower priority */ | 924 | /* 0 = normal, + = higher priority, - = lower priority */ |
| 924 | 925 | ||
