diff options
Diffstat (limited to 'drivers/gpu/drm/radeon/radeon_uvd.c')
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_uvd.c | 88 |
1 files changed, 66 insertions, 22 deletions
diff --git a/drivers/gpu/drm/radeon/radeon_uvd.c b/drivers/gpu/drm/radeon/radeon_uvd.c index 6fe9e4e76284..73dfe01435ea 100644 --- a/drivers/gpu/drm/radeon/radeon_uvd.c +++ b/drivers/gpu/drm/radeon/radeon_uvd.c @@ -34,6 +34,7 @@ #include <drm/drm.h> #include "radeon.h" +#include "radeon_ucode.h" #include "r600d.h" /* 1 second timeout */ @@ -47,7 +48,8 @@ #define FIRMWARE_CYPRESS "radeon/CYPRESS_uvd.bin" #define FIRMWARE_SUMO "radeon/SUMO_uvd.bin" #define FIRMWARE_TAHITI "radeon/TAHITI_uvd.bin" -#define FIRMWARE_BONAIRE "radeon/BONAIRE_uvd.bin" +#define FIRMWARE_BONAIRE_LEGACY "radeon/BONAIRE_uvd.bin" +#define FIRMWARE_BONAIRE "radeon/bonaire_uvd.bin" MODULE_FIRMWARE(FIRMWARE_R600); MODULE_FIRMWARE(FIRMWARE_RS780); @@ -56,6 +58,7 @@ MODULE_FIRMWARE(FIRMWARE_RV710); MODULE_FIRMWARE(FIRMWARE_CYPRESS); MODULE_FIRMWARE(FIRMWARE_SUMO); MODULE_FIRMWARE(FIRMWARE_TAHITI); +MODULE_FIRMWARE(FIRMWARE_BONAIRE_LEGACY); MODULE_FIRMWARE(FIRMWARE_BONAIRE); static void radeon_uvd_idle_work_handler(struct work_struct *work); @@ -63,7 +66,7 @@ static void radeon_uvd_idle_work_handler(struct work_struct *work); int radeon_uvd_init(struct radeon_device *rdev) { unsigned long bo_size; - const char *fw_name; + const char *fw_name = NULL, *legacy_fw_name = NULL; int i, r; INIT_DELAYED_WORK(&rdev->uvd.idle_work, radeon_uvd_idle_work_handler); @@ -74,22 +77,22 @@ int radeon_uvd_init(struct radeon_device *rdev) case CHIP_RV670: case CHIP_RV620: case CHIP_RV635: - fw_name = FIRMWARE_R600; + legacy_fw_name = FIRMWARE_R600; break; case CHIP_RS780: case CHIP_RS880: - fw_name = FIRMWARE_RS780; + legacy_fw_name = FIRMWARE_RS780; break; case CHIP_RV770: - fw_name = FIRMWARE_RV770; + legacy_fw_name = FIRMWARE_RV770; break; case CHIP_RV710: case CHIP_RV730: case CHIP_RV740: - fw_name = FIRMWARE_RV710; + legacy_fw_name = FIRMWARE_RV710; break; case CHIP_CYPRESS: @@ -97,7 +100,7 @@ int radeon_uvd_init(struct radeon_device *rdev) case CHIP_JUNIPER: case CHIP_REDWOOD: case CHIP_CEDAR: - fw_name = FIRMWARE_CYPRESS; + legacy_fw_name = FIRMWARE_CYPRESS; break; case CHIP_SUMO: @@ -107,7 +110,7 @@ int radeon_uvd_init(struct radeon_device *rdev) case CHIP_BARTS: case CHIP_TURKS: case CHIP_CAICOS: - fw_name = FIRMWARE_SUMO; + legacy_fw_name = FIRMWARE_SUMO; break; case CHIP_TAHITI: @@ -115,7 +118,7 @@ int radeon_uvd_init(struct radeon_device *rdev) case CHIP_PITCAIRN: case CHIP_ARUBA: case CHIP_OLAND: - fw_name = FIRMWARE_TAHITI; + legacy_fw_name = FIRMWARE_TAHITI; break; case CHIP_BONAIRE: @@ -123,6 +126,7 @@ int radeon_uvd_init(struct radeon_device *rdev) case CHIP_KAVERI: case CHIP_HAWAII: case CHIP_MULLINS: + legacy_fw_name = FIRMWARE_BONAIRE_LEGACY; fw_name = FIRMWARE_BONAIRE; break; @@ -130,16 +134,56 @@ int radeon_uvd_init(struct radeon_device *rdev) return -EINVAL; } - r = request_firmware(&rdev->uvd_fw, fw_name, rdev->dev); - if (r) { - dev_err(rdev->dev, "radeon_uvd: Can't load firmware \"%s\"\n", - fw_name); - return r; + rdev->uvd.fw_header_present = false; + rdev->uvd.max_handles = RADEON_DEFAULT_UVD_HANDLES; + if (fw_name) { + /* Let's try to load the newer firmware first */ + r = request_firmware(&rdev->uvd_fw, fw_name, rdev->dev); + if (r) { + dev_err(rdev->dev, "radeon_uvd: Can't load firmware \"%s\"\n", + fw_name); + } else { + struct common_firmware_header *hdr = (void *)rdev->uvd_fw->data; + unsigned version_major, version_minor, family_id; + + r = radeon_ucode_validate(rdev->uvd_fw); + if (r) + return r; + + rdev->uvd.fw_header_present = true; + + family_id = le32_to_cpu(hdr->ucode_version) & 0xff; + version_major = (le32_to_cpu(hdr->ucode_version) >> 24) & 0xff; + version_minor = (le32_to_cpu(hdr->ucode_version) >> 8) & 0xff; + DRM_INFO("Found UVD firmware Version: %hu.%hu Family ID: %hu\n", + version_major, version_minor, family_id); + + /* + * Limit the number of UVD handles depending on + * microcode major and minor versions. + */ + if ((version_major >= 0x01) && (version_minor >= 0x37)) + rdev->uvd.max_handles = RADEON_MAX_UVD_HANDLES; + } + } + + /* + * In case there is only legacy firmware, or we encounter an error + * while loading the new firmware, we fall back to loading the legacy + * firmware now. + */ + if (!fw_name || r) { + r = request_firmware(&rdev->uvd_fw, legacy_fw_name, rdev->dev); + if (r) { + dev_err(rdev->dev, "radeon_uvd: Can't load firmware \"%s\"\n", + legacy_fw_name); + return r; + } } bo_size = RADEON_GPU_PAGE_ALIGN(rdev->uvd_fw->size + 8) + RADEON_UVD_STACK_SIZE + RADEON_UVD_HEAP_SIZE + - RADEON_GPU_PAGE_SIZE; + RADEON_UVD_SESSION_SIZE * rdev->uvd.max_handles; r = radeon_bo_create(rdev, bo_size, PAGE_SIZE, true, RADEON_GEM_DOMAIN_VRAM, 0, NULL, NULL, &rdev->uvd.vcpu_bo); @@ -172,7 +216,7 @@ int radeon_uvd_init(struct radeon_device *rdev) radeon_bo_unreserve(rdev->uvd.vcpu_bo); - for (i = 0; i < RADEON_MAX_UVD_HANDLES; ++i) { + for (i = 0; i < rdev->uvd.max_handles; ++i) { atomic_set(&rdev->uvd.handles[i], 0); rdev->uvd.filp[i] = NULL; rdev->uvd.img_size[i] = 0; @@ -209,7 +253,7 @@ int radeon_uvd_suspend(struct radeon_device *rdev) if (rdev->uvd.vcpu_bo == NULL) return 0; - for (i = 0; i < RADEON_MAX_UVD_HANDLES; ++i) { + for (i = 0; i < rdev->uvd.max_handles; ++i) { uint32_t handle = atomic_read(&rdev->uvd.handles[i]); if (handle != 0) { struct radeon_fence *fence; @@ -284,7 +328,7 @@ void radeon_uvd_force_into_uvd_segment(struct radeon_bo *rbo, void radeon_uvd_free_handles(struct radeon_device *rdev, struct drm_file *filp) { int i, r; - for (i = 0; i < RADEON_MAX_UVD_HANDLES; ++i) { + for (i = 0; i < rdev->uvd.max_handles; ++i) { uint32_t handle = atomic_read(&rdev->uvd.handles[i]); if (handle != 0 && rdev->uvd.filp[i] == filp) { struct radeon_fence *fence; @@ -469,7 +513,7 @@ static int radeon_uvd_cs_msg(struct radeon_cs_parser *p, struct radeon_bo *bo, return r; /* try to alloc a new handle */ - for (i = 0; i < RADEON_MAX_UVD_HANDLES; ++i) { + for (i = 0; i < p->rdev->uvd.max_handles; ++i) { if (atomic_read(&p->rdev->uvd.handles[i]) == handle) { DRM_ERROR("Handle 0x%x already in use!\n", handle); return -EINVAL; @@ -495,7 +539,7 @@ static int radeon_uvd_cs_msg(struct radeon_cs_parser *p, struct radeon_bo *bo, return r; /* validate the handle */ - for (i = 0; i < RADEON_MAX_UVD_HANDLES; ++i) { + for (i = 0; i < p->rdev->uvd.max_handles; ++i) { if (atomic_read(&p->rdev->uvd.handles[i]) == handle) { if (p->rdev->uvd.filp[i] != p->filp) { DRM_ERROR("UVD handle collision detected!\n"); @@ -510,7 +554,7 @@ static int radeon_uvd_cs_msg(struct radeon_cs_parser *p, struct radeon_bo *bo, case 2: /* it's a destroy msg, free the handle */ - for (i = 0; i < RADEON_MAX_UVD_HANDLES; ++i) + for (i = 0; i < p->rdev->uvd.max_handles; ++i) atomic_cmpxchg(&p->rdev->uvd.handles[i], handle, 0); radeon_bo_kunmap(bo); return 0; @@ -809,7 +853,7 @@ static void radeon_uvd_count_handles(struct radeon_device *rdev, *sd = 0; *hd = 0; - for (i = 0; i < RADEON_MAX_UVD_HANDLES; ++i) { + for (i = 0; i < rdev->uvd.max_handles; ++i) { if (!atomic_read(&rdev->uvd.handles[i])) continue; |