1 1.7 riastrad /* $NetBSD: radeon_uvd.c,v 1.7 2021/12/18 23:45:43 riastradh Exp $ */ 2 1.3 riastrad 3 1.1 riastrad /* 4 1.1 riastrad * Copyright 2011 Advanced Micro Devices, Inc. 5 1.1 riastrad * All Rights Reserved. 6 1.1 riastrad * 7 1.1 riastrad * Permission is hereby granted, free of charge, to any person obtaining a 8 1.1 riastrad * copy of this software and associated documentation files (the 9 1.1 riastrad * "Software"), to deal in the Software without restriction, including 10 1.1 riastrad * without limitation the rights to use, copy, modify, merge, publish, 11 1.1 riastrad * distribute, sub license, and/or sell copies of the Software, and to 12 1.1 riastrad * permit persons to whom the Software is furnished to do so, subject to 13 1.1 riastrad * the following conditions: 14 1.1 riastrad * 15 1.1 riastrad * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 1.1 riastrad * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 1.1 riastrad * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 18 1.1 riastrad * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, 19 1.1 riastrad * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 20 1.1 riastrad * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 21 1.1 riastrad * USE OR OTHER DEALINGS IN THE SOFTWARE. 22 1.1 riastrad * 23 1.1 riastrad * The above copyright notice and this permission notice (including the 24 1.1 riastrad * next paragraph) shall be included in all copies or substantial portions 25 1.1 riastrad * of the Software. 26 1.1 riastrad * 27 1.1 riastrad */ 28 1.1 riastrad /* 29 1.1 riastrad * Authors: 30 1.1 riastrad * Christian Knig <deathsimple (at) vodafone.de> 31 1.1 riastrad */ 32 1.1 riastrad 33 1.3 riastrad #include <sys/cdefs.h> 34 1.7 riastrad __KERNEL_RCSID(0, "$NetBSD: radeon_uvd.c,v 1.7 2021/12/18 23:45:43 riastradh Exp $"); 35 1.3 riastrad 36 1.1 riastrad #include <linux/firmware.h> 37 1.1 riastrad #include <linux/module.h> 38 1.7 riastrad 39 1.1 riastrad #include <drm/drm.h> 40 1.1 riastrad 41 1.1 riastrad #include "radeon.h" 42 1.7 riastrad #include "radeon_ucode.h" 43 1.1 riastrad #include "r600d.h" 44 1.1 riastrad 45 1.6 riastrad #include <linux/nbsd-namespace.h> 46 1.6 riastrad 47 1.1 riastrad /* 1 second timeout */ 48 1.1 riastrad #define UVD_IDLE_TIMEOUT_MS 1000 49 1.1 riastrad 50 1.1 riastrad /* Firmware Names */ 51 1.3 riastrad #define FIRMWARE_R600 "radeon/R600_uvd.bin" 52 1.3 riastrad #define FIRMWARE_RS780 "radeon/RS780_uvd.bin" 53 1.3 riastrad #define FIRMWARE_RV770 "radeon/RV770_uvd.bin" 54 1.1 riastrad #define FIRMWARE_RV710 "radeon/RV710_uvd.bin" 55 1.1 riastrad #define FIRMWARE_CYPRESS "radeon/CYPRESS_uvd.bin" 56 1.1 riastrad #define FIRMWARE_SUMO "radeon/SUMO_uvd.bin" 57 1.1 riastrad #define FIRMWARE_TAHITI "radeon/TAHITI_uvd.bin" 58 1.7 riastrad #define FIRMWARE_BONAIRE_LEGACY "radeon/BONAIRE_uvd.bin" 59 1.7 riastrad #define FIRMWARE_BONAIRE "radeon/bonaire_uvd.bin" 60 1.1 riastrad 61 1.3 riastrad MODULE_FIRMWARE(FIRMWARE_R600); 62 1.3 riastrad MODULE_FIRMWARE(FIRMWARE_RS780); 63 1.3 riastrad MODULE_FIRMWARE(FIRMWARE_RV770); 64 1.1 riastrad MODULE_FIRMWARE(FIRMWARE_RV710); 65 1.1 riastrad MODULE_FIRMWARE(FIRMWARE_CYPRESS); 66 1.1 riastrad MODULE_FIRMWARE(FIRMWARE_SUMO); 67 1.1 riastrad MODULE_FIRMWARE(FIRMWARE_TAHITI); 68 1.7 riastrad MODULE_FIRMWARE(FIRMWARE_BONAIRE_LEGACY); 69 1.1 riastrad MODULE_FIRMWARE(FIRMWARE_BONAIRE); 70 1.1 riastrad 71 1.1 riastrad static void radeon_uvd_idle_work_handler(struct work_struct *work); 72 1.1 riastrad 73 1.1 riastrad int radeon_uvd_init(struct radeon_device *rdev) 74 1.1 riastrad { 75 1.1 riastrad unsigned long bo_size; 76 1.7 riastrad const char *fw_name = NULL, *legacy_fw_name = NULL; 77 1.1 riastrad int i, r; 78 1.1 riastrad 79 1.1 riastrad INIT_DELAYED_WORK(&rdev->uvd.idle_work, radeon_uvd_idle_work_handler); 80 1.1 riastrad 81 1.1 riastrad switch (rdev->family) { 82 1.3 riastrad case CHIP_RV610: 83 1.3 riastrad case CHIP_RV630: 84 1.3 riastrad case CHIP_RV670: 85 1.3 riastrad case CHIP_RV620: 86 1.3 riastrad case CHIP_RV635: 87 1.7 riastrad legacy_fw_name = FIRMWARE_R600; 88 1.3 riastrad break; 89 1.3 riastrad 90 1.3 riastrad case CHIP_RS780: 91 1.3 riastrad case CHIP_RS880: 92 1.7 riastrad legacy_fw_name = FIRMWARE_RS780; 93 1.3 riastrad break; 94 1.3 riastrad 95 1.3 riastrad case CHIP_RV770: 96 1.7 riastrad legacy_fw_name = FIRMWARE_RV770; 97 1.3 riastrad break; 98 1.3 riastrad 99 1.1 riastrad case CHIP_RV710: 100 1.1 riastrad case CHIP_RV730: 101 1.1 riastrad case CHIP_RV740: 102 1.7 riastrad legacy_fw_name = FIRMWARE_RV710; 103 1.1 riastrad break; 104 1.1 riastrad 105 1.1 riastrad case CHIP_CYPRESS: 106 1.1 riastrad case CHIP_HEMLOCK: 107 1.1 riastrad case CHIP_JUNIPER: 108 1.1 riastrad case CHIP_REDWOOD: 109 1.1 riastrad case CHIP_CEDAR: 110 1.7 riastrad legacy_fw_name = FIRMWARE_CYPRESS; 111 1.1 riastrad break; 112 1.1 riastrad 113 1.1 riastrad case CHIP_SUMO: 114 1.1 riastrad case CHIP_SUMO2: 115 1.1 riastrad case CHIP_PALM: 116 1.1 riastrad case CHIP_CAYMAN: 117 1.1 riastrad case CHIP_BARTS: 118 1.1 riastrad case CHIP_TURKS: 119 1.1 riastrad case CHIP_CAICOS: 120 1.7 riastrad legacy_fw_name = FIRMWARE_SUMO; 121 1.1 riastrad break; 122 1.1 riastrad 123 1.1 riastrad case CHIP_TAHITI: 124 1.1 riastrad case CHIP_VERDE: 125 1.1 riastrad case CHIP_PITCAIRN: 126 1.1 riastrad case CHIP_ARUBA: 127 1.1 riastrad case CHIP_OLAND: 128 1.7 riastrad legacy_fw_name = FIRMWARE_TAHITI; 129 1.1 riastrad break; 130 1.1 riastrad 131 1.1 riastrad case CHIP_BONAIRE: 132 1.1 riastrad case CHIP_KABINI: 133 1.1 riastrad case CHIP_KAVERI: 134 1.1 riastrad case CHIP_HAWAII: 135 1.1 riastrad case CHIP_MULLINS: 136 1.7 riastrad legacy_fw_name = FIRMWARE_BONAIRE_LEGACY; 137 1.1 riastrad fw_name = FIRMWARE_BONAIRE; 138 1.1 riastrad break; 139 1.1 riastrad 140 1.1 riastrad default: 141 1.1 riastrad return -EINVAL; 142 1.1 riastrad } 143 1.1 riastrad 144 1.7 riastrad rdev->uvd.fw_header_present = false; 145 1.7 riastrad rdev->uvd.max_handles = RADEON_DEFAULT_UVD_HANDLES; 146 1.7 riastrad if (fw_name) { 147 1.7 riastrad /* Let's try to load the newer firmware first */ 148 1.7 riastrad r = request_firmware(&rdev->uvd_fw, fw_name, rdev->dev); 149 1.7 riastrad if (r) { 150 1.7 riastrad dev_err(rdev->dev, "radeon_uvd: Can't load firmware \"%s\"\n", 151 1.7 riastrad fw_name); 152 1.7 riastrad } else { 153 1.7 riastrad struct common_firmware_header *hdr = (void *)rdev->uvd_fw->data; 154 1.7 riastrad unsigned version_major, version_minor, family_id; 155 1.7 riastrad 156 1.7 riastrad r = radeon_ucode_validate(rdev->uvd_fw); 157 1.7 riastrad if (r) 158 1.7 riastrad return r; 159 1.7 riastrad 160 1.7 riastrad rdev->uvd.fw_header_present = true; 161 1.7 riastrad 162 1.7 riastrad family_id = le32_to_cpu(hdr->ucode_version) & 0xff; 163 1.7 riastrad version_major = (le32_to_cpu(hdr->ucode_version) >> 24) & 0xff; 164 1.7 riastrad version_minor = (le32_to_cpu(hdr->ucode_version) >> 8) & 0xff; 165 1.7 riastrad DRM_INFO("Found UVD firmware Version: %hu.%hu Family ID: %hu\n", 166 1.7 riastrad version_major, version_minor, family_id); 167 1.7 riastrad 168 1.7 riastrad /* 169 1.7 riastrad * Limit the number of UVD handles depending on 170 1.7 riastrad * microcode major and minor versions. 171 1.7 riastrad */ 172 1.7 riastrad if ((version_major >= 0x01) && (version_minor >= 0x37)) 173 1.7 riastrad rdev->uvd.max_handles = RADEON_MAX_UVD_HANDLES; 174 1.7 riastrad } 175 1.7 riastrad } 176 1.7 riastrad 177 1.7 riastrad /* 178 1.7 riastrad * In case there is only legacy firmware, or we encounter an error 179 1.7 riastrad * while loading the new firmware, we fall back to loading the legacy 180 1.7 riastrad * firmware now. 181 1.7 riastrad */ 182 1.7 riastrad if (!fw_name || r) { 183 1.7 riastrad r = request_firmware(&rdev->uvd_fw, legacy_fw_name, rdev->dev); 184 1.7 riastrad if (r) { 185 1.7 riastrad dev_err(rdev->dev, "radeon_uvd: Can't load firmware \"%s\"\n", 186 1.7 riastrad legacy_fw_name); 187 1.7 riastrad return r; 188 1.7 riastrad } 189 1.1 riastrad } 190 1.1 riastrad 191 1.1 riastrad bo_size = RADEON_GPU_PAGE_ALIGN(rdev->uvd_fw->size + 8) + 192 1.3 riastrad RADEON_UVD_STACK_SIZE + RADEON_UVD_HEAP_SIZE + 193 1.7 riastrad RADEON_UVD_SESSION_SIZE * rdev->uvd.max_handles; 194 1.1 riastrad r = radeon_bo_create(rdev, bo_size, PAGE_SIZE, true, 195 1.3 riastrad RADEON_GEM_DOMAIN_VRAM, 0, NULL, 196 1.3 riastrad NULL, &rdev->uvd.vcpu_bo); 197 1.1 riastrad if (r) { 198 1.1 riastrad dev_err(rdev->dev, "(%d) failed to allocate UVD bo\n", r); 199 1.1 riastrad return r; 200 1.1 riastrad } 201 1.1 riastrad 202 1.1 riastrad r = radeon_bo_reserve(rdev->uvd.vcpu_bo, false); 203 1.1 riastrad if (r) { 204 1.1 riastrad radeon_bo_unref(&rdev->uvd.vcpu_bo); 205 1.1 riastrad dev_err(rdev->dev, "(%d) failed to reserve UVD bo\n", r); 206 1.1 riastrad return r; 207 1.1 riastrad } 208 1.1 riastrad 209 1.1 riastrad r = radeon_bo_pin(rdev->uvd.vcpu_bo, RADEON_GEM_DOMAIN_VRAM, 210 1.1 riastrad &rdev->uvd.gpu_addr); 211 1.1 riastrad if (r) { 212 1.1 riastrad radeon_bo_unreserve(rdev->uvd.vcpu_bo); 213 1.1 riastrad radeon_bo_unref(&rdev->uvd.vcpu_bo); 214 1.1 riastrad dev_err(rdev->dev, "(%d) UVD bo pin failed\n", r); 215 1.1 riastrad return r; 216 1.1 riastrad } 217 1.1 riastrad 218 1.1 riastrad r = radeon_bo_kmap(rdev->uvd.vcpu_bo, &rdev->uvd.cpu_addr); 219 1.1 riastrad if (r) { 220 1.1 riastrad dev_err(rdev->dev, "(%d) UVD map failed\n", r); 221 1.1 riastrad return r; 222 1.1 riastrad } 223 1.1 riastrad 224 1.1 riastrad radeon_bo_unreserve(rdev->uvd.vcpu_bo); 225 1.1 riastrad 226 1.7 riastrad for (i = 0; i < rdev->uvd.max_handles; ++i) { 227 1.1 riastrad atomic_set(&rdev->uvd.handles[i], 0); 228 1.1 riastrad rdev->uvd.filp[i] = NULL; 229 1.1 riastrad rdev->uvd.img_size[i] = 0; 230 1.1 riastrad } 231 1.1 riastrad 232 1.1 riastrad return 0; 233 1.1 riastrad } 234 1.1 riastrad 235 1.1 riastrad void radeon_uvd_fini(struct radeon_device *rdev) 236 1.1 riastrad { 237 1.1 riastrad int r; 238 1.1 riastrad 239 1.1 riastrad if (rdev->uvd.vcpu_bo == NULL) 240 1.1 riastrad return; 241 1.1 riastrad 242 1.1 riastrad r = radeon_bo_reserve(rdev->uvd.vcpu_bo, false); 243 1.1 riastrad if (!r) { 244 1.1 riastrad radeon_bo_kunmap(rdev->uvd.vcpu_bo); 245 1.1 riastrad radeon_bo_unpin(rdev->uvd.vcpu_bo); 246 1.1 riastrad radeon_bo_unreserve(rdev->uvd.vcpu_bo); 247 1.1 riastrad } 248 1.1 riastrad 249 1.1 riastrad radeon_bo_unref(&rdev->uvd.vcpu_bo); 250 1.1 riastrad 251 1.1 riastrad radeon_ring_fini(rdev, &rdev->ring[R600_RING_TYPE_UVD_INDEX]); 252 1.1 riastrad 253 1.1 riastrad release_firmware(rdev->uvd_fw); 254 1.1 riastrad } 255 1.1 riastrad 256 1.1 riastrad int radeon_uvd_suspend(struct radeon_device *rdev) 257 1.1 riastrad { 258 1.3 riastrad int i, r; 259 1.1 riastrad 260 1.1 riastrad if (rdev->uvd.vcpu_bo == NULL) 261 1.1 riastrad return 0; 262 1.1 riastrad 263 1.7 riastrad for (i = 0; i < rdev->uvd.max_handles; ++i) { 264 1.3 riastrad uint32_t handle = atomic_read(&rdev->uvd.handles[i]); 265 1.3 riastrad if (handle != 0) { 266 1.3 riastrad struct radeon_fence *fence; 267 1.1 riastrad 268 1.3 riastrad radeon_uvd_note_usage(rdev); 269 1.1 riastrad 270 1.3 riastrad r = radeon_uvd_get_destroy_msg(rdev, 271 1.3 riastrad R600_RING_TYPE_UVD_INDEX, handle, &fence); 272 1.3 riastrad if (r) { 273 1.3 riastrad DRM_ERROR("Error destroying UVD (%d)!\n", r); 274 1.3 riastrad continue; 275 1.3 riastrad } 276 1.1 riastrad 277 1.3 riastrad radeon_fence_wait(fence, false); 278 1.3 riastrad radeon_fence_unref(&fence); 279 1.1 riastrad 280 1.3 riastrad rdev->uvd.filp[i] = NULL; 281 1.3 riastrad atomic_set(&rdev->uvd.handles[i], 0); 282 1.3 riastrad } 283 1.3 riastrad } 284 1.1 riastrad 285 1.1 riastrad return 0; 286 1.1 riastrad } 287 1.1 riastrad 288 1.1 riastrad int radeon_uvd_resume(struct radeon_device *rdev) 289 1.1 riastrad { 290 1.1 riastrad unsigned size; 291 1.5 riastrad void *ptr; 292 1.1 riastrad 293 1.1 riastrad if (rdev->uvd.vcpu_bo == NULL) 294 1.1 riastrad return -EINVAL; 295 1.1 riastrad 296 1.1 riastrad memcpy(rdev->uvd.cpu_addr, rdev->uvd_fw->data, rdev->uvd_fw->size); 297 1.1 riastrad 298 1.1 riastrad size = radeon_bo_size(rdev->uvd.vcpu_bo); 299 1.1 riastrad size -= rdev->uvd_fw->size; 300 1.1 riastrad 301 1.1 riastrad ptr = rdev->uvd.cpu_addr; 302 1.1 riastrad ptr += rdev->uvd_fw->size; 303 1.1 riastrad 304 1.3 riastrad memset(ptr, 0, size); 305 1.1 riastrad 306 1.1 riastrad return 0; 307 1.1 riastrad } 308 1.1 riastrad 309 1.3 riastrad void radeon_uvd_force_into_uvd_segment(struct radeon_bo *rbo, 310 1.3 riastrad uint32_t allowed_domains) 311 1.1 riastrad { 312 1.3 riastrad int i; 313 1.3 riastrad 314 1.3 riastrad for (i = 0; i < rbo->placement.num_placement; ++i) { 315 1.3 riastrad rbo->placements[i].fpfn = 0 >> PAGE_SHIFT; 316 1.3 riastrad rbo->placements[i].lpfn = (256 * 1024 * 1024) >> PAGE_SHIFT; 317 1.3 riastrad } 318 1.3 riastrad 319 1.3 riastrad /* If it must be in VRAM it must be in the first segment as well */ 320 1.3 riastrad if (allowed_domains == RADEON_GEM_DOMAIN_VRAM) 321 1.3 riastrad return; 322 1.3 riastrad 323 1.3 riastrad /* abort if we already have more than one placement */ 324 1.3 riastrad if (rbo->placement.num_placement > 1) 325 1.3 riastrad return; 326 1.3 riastrad 327 1.3 riastrad /* add another 256MB segment */ 328 1.3 riastrad rbo->placements[1] = rbo->placements[0]; 329 1.3 riastrad rbo->placements[1].fpfn += (256 * 1024 * 1024) >> PAGE_SHIFT; 330 1.3 riastrad rbo->placements[1].lpfn += (256 * 1024 * 1024) >> PAGE_SHIFT; 331 1.3 riastrad rbo->placement.num_placement++; 332 1.3 riastrad rbo->placement.num_busy_placement++; 333 1.1 riastrad } 334 1.1 riastrad 335 1.1 riastrad void radeon_uvd_free_handles(struct radeon_device *rdev, struct drm_file *filp) 336 1.1 riastrad { 337 1.1 riastrad int i, r; 338 1.7 riastrad for (i = 0; i < rdev->uvd.max_handles; ++i) { 339 1.1 riastrad uint32_t handle = atomic_read(&rdev->uvd.handles[i]); 340 1.1 riastrad if (handle != 0 && rdev->uvd.filp[i] == filp) { 341 1.1 riastrad struct radeon_fence *fence; 342 1.1 riastrad 343 1.1 riastrad radeon_uvd_note_usage(rdev); 344 1.1 riastrad 345 1.1 riastrad r = radeon_uvd_get_destroy_msg(rdev, 346 1.1 riastrad R600_RING_TYPE_UVD_INDEX, handle, &fence); 347 1.1 riastrad if (r) { 348 1.1 riastrad DRM_ERROR("Error destroying UVD (%d)!\n", r); 349 1.1 riastrad continue; 350 1.1 riastrad } 351 1.1 riastrad 352 1.1 riastrad radeon_fence_wait(fence, false); 353 1.1 riastrad radeon_fence_unref(&fence); 354 1.1 riastrad 355 1.1 riastrad rdev->uvd.filp[i] = NULL; 356 1.1 riastrad atomic_set(&rdev->uvd.handles[i], 0); 357 1.1 riastrad } 358 1.1 riastrad } 359 1.1 riastrad } 360 1.1 riastrad 361 1.1 riastrad static int radeon_uvd_cs_msg_decode(uint32_t *msg, unsigned buf_sizes[]) 362 1.1 riastrad { 363 1.1 riastrad unsigned stream_type = msg[4]; 364 1.1 riastrad unsigned width = msg[6]; 365 1.1 riastrad unsigned height = msg[7]; 366 1.1 riastrad unsigned dpb_size = msg[9]; 367 1.1 riastrad unsigned pitch = msg[28]; 368 1.1 riastrad 369 1.1 riastrad unsigned width_in_mb = width / 16; 370 1.1 riastrad unsigned height_in_mb = ALIGN(height / 16, 2); 371 1.1 riastrad 372 1.1 riastrad unsigned image_size, tmp, min_dpb_size; 373 1.1 riastrad 374 1.1 riastrad image_size = width * height; 375 1.1 riastrad image_size += image_size / 2; 376 1.1 riastrad image_size = ALIGN(image_size, 1024); 377 1.1 riastrad 378 1.1 riastrad switch (stream_type) { 379 1.1 riastrad case 0: /* H264 */ 380 1.1 riastrad 381 1.1 riastrad /* reference picture buffer */ 382 1.1 riastrad min_dpb_size = image_size * 17; 383 1.1 riastrad 384 1.1 riastrad /* macroblock context buffer */ 385 1.1 riastrad min_dpb_size += width_in_mb * height_in_mb * 17 * 192; 386 1.1 riastrad 387 1.1 riastrad /* IT surface buffer */ 388 1.1 riastrad min_dpb_size += width_in_mb * height_in_mb * 32; 389 1.1 riastrad break; 390 1.1 riastrad 391 1.1 riastrad case 1: /* VC1 */ 392 1.1 riastrad 393 1.1 riastrad /* reference picture buffer */ 394 1.1 riastrad min_dpb_size = image_size * 3; 395 1.1 riastrad 396 1.1 riastrad /* CONTEXT_BUFFER */ 397 1.1 riastrad min_dpb_size += width_in_mb * height_in_mb * 128; 398 1.1 riastrad 399 1.1 riastrad /* IT surface buffer */ 400 1.1 riastrad min_dpb_size += width_in_mb * 64; 401 1.1 riastrad 402 1.1 riastrad /* DB surface buffer */ 403 1.1 riastrad min_dpb_size += width_in_mb * 128; 404 1.1 riastrad 405 1.1 riastrad /* BP */ 406 1.1 riastrad tmp = max(width_in_mb, height_in_mb); 407 1.1 riastrad min_dpb_size += ALIGN(tmp * 7 * 16, 64); 408 1.1 riastrad break; 409 1.1 riastrad 410 1.1 riastrad case 3: /* MPEG2 */ 411 1.1 riastrad 412 1.1 riastrad /* reference picture buffer */ 413 1.1 riastrad min_dpb_size = image_size * 3; 414 1.1 riastrad break; 415 1.1 riastrad 416 1.1 riastrad case 4: /* MPEG4 */ 417 1.1 riastrad 418 1.1 riastrad /* reference picture buffer */ 419 1.1 riastrad min_dpb_size = image_size * 3; 420 1.1 riastrad 421 1.1 riastrad /* CM */ 422 1.1 riastrad min_dpb_size += width_in_mb * height_in_mb * 64; 423 1.1 riastrad 424 1.1 riastrad /* IT surface buffer */ 425 1.1 riastrad min_dpb_size += ALIGN(width_in_mb * height_in_mb * 32, 64); 426 1.1 riastrad break; 427 1.1 riastrad 428 1.1 riastrad default: 429 1.1 riastrad DRM_ERROR("UVD codec not handled %d!\n", stream_type); 430 1.1 riastrad return -EINVAL; 431 1.1 riastrad } 432 1.1 riastrad 433 1.1 riastrad if (width > pitch) { 434 1.1 riastrad DRM_ERROR("Invalid UVD decoding target pitch!\n"); 435 1.1 riastrad return -EINVAL; 436 1.1 riastrad } 437 1.1 riastrad 438 1.1 riastrad if (dpb_size < min_dpb_size) { 439 1.1 riastrad DRM_ERROR("Invalid dpb_size in UVD message (%d / %d)!\n", 440 1.1 riastrad dpb_size, min_dpb_size); 441 1.1 riastrad return -EINVAL; 442 1.1 riastrad } 443 1.1 riastrad 444 1.1 riastrad buf_sizes[0x1] = dpb_size; 445 1.1 riastrad buf_sizes[0x2] = image_size; 446 1.1 riastrad return 0; 447 1.1 riastrad } 448 1.1 riastrad 449 1.3 riastrad static int radeon_uvd_validate_codec(struct radeon_cs_parser *p, 450 1.3 riastrad unsigned stream_type) 451 1.3 riastrad { 452 1.3 riastrad switch (stream_type) { 453 1.3 riastrad case 0: /* H264 */ 454 1.3 riastrad case 1: /* VC1 */ 455 1.3 riastrad /* always supported */ 456 1.3 riastrad return 0; 457 1.3 riastrad 458 1.3 riastrad case 3: /* MPEG2 */ 459 1.3 riastrad case 4: /* MPEG4 */ 460 1.3 riastrad /* only since UVD 3 */ 461 1.3 riastrad if (p->rdev->family >= CHIP_PALM) 462 1.3 riastrad return 0; 463 1.3 riastrad 464 1.3 riastrad /* fall through */ 465 1.3 riastrad default: 466 1.3 riastrad DRM_ERROR("UVD codec not supported by hardware %d!\n", 467 1.3 riastrad stream_type); 468 1.3 riastrad return -EINVAL; 469 1.3 riastrad } 470 1.3 riastrad } 471 1.3 riastrad 472 1.1 riastrad static int radeon_uvd_cs_msg(struct radeon_cs_parser *p, struct radeon_bo *bo, 473 1.1 riastrad unsigned offset, unsigned buf_sizes[]) 474 1.1 riastrad { 475 1.1 riastrad int32_t *msg, msg_type, handle; 476 1.1 riastrad unsigned img_size = 0; 477 1.7 riastrad struct dma_fence *f; 478 1.1 riastrad void *ptr; 479 1.1 riastrad 480 1.1 riastrad int i, r; 481 1.1 riastrad 482 1.1 riastrad if (offset & 0x3F) { 483 1.1 riastrad DRM_ERROR("UVD messages must be 64 byte aligned!\n"); 484 1.1 riastrad return -EINVAL; 485 1.1 riastrad } 486 1.1 riastrad 487 1.7 riastrad f = dma_resv_get_excl(bo->tbo.base.resv); 488 1.3 riastrad if (f) { 489 1.3 riastrad r = radeon_fence_wait((struct radeon_fence *)f, false); 490 1.1 riastrad if (r) { 491 1.1 riastrad DRM_ERROR("Failed waiting for UVD message (%d)!\n", r); 492 1.1 riastrad return r; 493 1.1 riastrad } 494 1.1 riastrad } 495 1.1 riastrad 496 1.1 riastrad r = radeon_bo_kmap(bo, &ptr); 497 1.1 riastrad if (r) { 498 1.1 riastrad DRM_ERROR("Failed mapping the UVD message (%d)!\n", r); 499 1.1 riastrad return r; 500 1.1 riastrad } 501 1.1 riastrad 502 1.5 riastrad msg = ptr + offset; 503 1.1 riastrad 504 1.1 riastrad msg_type = msg[1]; 505 1.1 riastrad handle = msg[2]; 506 1.1 riastrad 507 1.1 riastrad if (handle == 0) { 508 1.1 riastrad DRM_ERROR("Invalid UVD handle!\n"); 509 1.1 riastrad return -EINVAL; 510 1.1 riastrad } 511 1.1 riastrad 512 1.3 riastrad switch (msg_type) { 513 1.3 riastrad case 0: 514 1.3 riastrad /* it's a create msg, calc image size (width * height) */ 515 1.3 riastrad img_size = msg[7] * msg[8]; 516 1.3 riastrad 517 1.3 riastrad r = radeon_uvd_validate_codec(p, msg[4]); 518 1.3 riastrad radeon_bo_kunmap(bo); 519 1.3 riastrad if (r) 520 1.3 riastrad return r; 521 1.3 riastrad 522 1.3 riastrad /* try to alloc a new handle */ 523 1.7 riastrad for (i = 0; i < p->rdev->uvd.max_handles; ++i) { 524 1.3 riastrad if (atomic_read(&p->rdev->uvd.handles[i]) == handle) { 525 1.3 riastrad DRM_ERROR("Handle 0x%x already in use!\n", handle); 526 1.3 riastrad return -EINVAL; 527 1.3 riastrad } 528 1.3 riastrad 529 1.3 riastrad if (!atomic_cmpxchg(&p->rdev->uvd.handles[i], 0, handle)) { 530 1.3 riastrad p->rdev->uvd.filp[i] = p->filp; 531 1.3 riastrad p->rdev->uvd.img_size[i] = img_size; 532 1.3 riastrad return 0; 533 1.3 riastrad } 534 1.3 riastrad } 535 1.3 riastrad 536 1.3 riastrad DRM_ERROR("No more free UVD handles!\n"); 537 1.3 riastrad return -EINVAL; 538 1.3 riastrad 539 1.3 riastrad case 1: 540 1.3 riastrad /* it's a decode msg, validate codec and calc buffer sizes */ 541 1.3 riastrad r = radeon_uvd_validate_codec(p, msg[4]); 542 1.3 riastrad if (!r) 543 1.3 riastrad r = radeon_uvd_cs_msg_decode(msg, buf_sizes); 544 1.1 riastrad radeon_bo_kunmap(bo); 545 1.1 riastrad if (r) 546 1.1 riastrad return r; 547 1.1 riastrad 548 1.3 riastrad /* validate the handle */ 549 1.7 riastrad for (i = 0; i < p->rdev->uvd.max_handles; ++i) { 550 1.3 riastrad if (atomic_read(&p->rdev->uvd.handles[i]) == handle) { 551 1.3 riastrad if (p->rdev->uvd.filp[i] != p->filp) { 552 1.3 riastrad DRM_ERROR("UVD handle collision detected!\n"); 553 1.3 riastrad return -EINVAL; 554 1.3 riastrad } 555 1.3 riastrad return 0; 556 1.3 riastrad } 557 1.3 riastrad } 558 1.3 riastrad 559 1.3 riastrad DRM_ERROR("Invalid UVD handle 0x%x!\n", handle); 560 1.3 riastrad return -ENOENT; 561 1.3 riastrad 562 1.3 riastrad case 2: 563 1.1 riastrad /* it's a destroy msg, free the handle */ 564 1.7 riastrad for (i = 0; i < p->rdev->uvd.max_handles; ++i) 565 1.1 riastrad atomic_cmpxchg(&p->rdev->uvd.handles[i], handle, 0); 566 1.1 riastrad radeon_bo_kunmap(bo); 567 1.1 riastrad return 0; 568 1.1 riastrad 569 1.3 riastrad default: 570 1.1 riastrad 571 1.3 riastrad DRM_ERROR("Illegal UVD message type (%d)!\n", msg_type); 572 1.3 riastrad return -EINVAL; 573 1.1 riastrad } 574 1.1 riastrad 575 1.3 riastrad BUG(); 576 1.1 riastrad return -EINVAL; 577 1.1 riastrad } 578 1.1 riastrad 579 1.1 riastrad static int radeon_uvd_cs_reloc(struct radeon_cs_parser *p, 580 1.1 riastrad int data0, int data1, 581 1.1 riastrad unsigned buf_sizes[], bool *has_msg_cmd) 582 1.1 riastrad { 583 1.1 riastrad struct radeon_cs_chunk *relocs_chunk; 584 1.3 riastrad struct radeon_bo_list *reloc; 585 1.1 riastrad unsigned idx, cmd, offset; 586 1.1 riastrad uint64_t start, end; 587 1.1 riastrad int r; 588 1.1 riastrad 589 1.3 riastrad relocs_chunk = p->chunk_relocs; 590 1.1 riastrad offset = radeon_get_ib_value(p, data0); 591 1.1 riastrad idx = radeon_get_ib_value(p, data1); 592 1.1 riastrad if (idx >= relocs_chunk->length_dw) { 593 1.1 riastrad DRM_ERROR("Relocs at %d after relocations chunk end %d !\n", 594 1.1 riastrad idx, relocs_chunk->length_dw); 595 1.1 riastrad return -EINVAL; 596 1.1 riastrad } 597 1.1 riastrad 598 1.3 riastrad reloc = &p->relocs[(idx / 4)]; 599 1.1 riastrad start = reloc->gpu_offset; 600 1.1 riastrad end = start + radeon_bo_size(reloc->robj); 601 1.1 riastrad start += offset; 602 1.1 riastrad 603 1.1 riastrad p->ib.ptr[data0] = start & 0xFFFFFFFF; 604 1.1 riastrad p->ib.ptr[data1] = start >> 32; 605 1.1 riastrad 606 1.1 riastrad cmd = radeon_get_ib_value(p, p->idx) >> 1; 607 1.1 riastrad 608 1.1 riastrad if (cmd < 0x4) { 609 1.1 riastrad if (end <= start) { 610 1.1 riastrad DRM_ERROR("invalid reloc offset %X!\n", offset); 611 1.1 riastrad return -EINVAL; 612 1.1 riastrad } 613 1.1 riastrad if ((end - start) < buf_sizes[cmd]) { 614 1.1 riastrad DRM_ERROR("buffer (%d) to small (%d / %d)!\n", cmd, 615 1.1 riastrad (unsigned)(end - start), buf_sizes[cmd]); 616 1.1 riastrad return -EINVAL; 617 1.1 riastrad } 618 1.1 riastrad 619 1.1 riastrad } else if (cmd != 0x100) { 620 1.1 riastrad DRM_ERROR("invalid UVD command %X!\n", cmd); 621 1.1 riastrad return -EINVAL; 622 1.1 riastrad } 623 1.1 riastrad 624 1.1 riastrad if ((start >> 28) != ((end - 1) >> 28)) { 625 1.2 riastrad DRM_ERROR("reloc %"PRIX64"-%"PRIX64" crossing 256MB boundary!\n", 626 1.1 riastrad start, end); 627 1.1 riastrad return -EINVAL; 628 1.1 riastrad } 629 1.1 riastrad 630 1.1 riastrad /* TODO: is this still necessary on NI+ ? */ 631 1.1 riastrad if ((cmd == 0 || cmd == 0x3) && 632 1.1 riastrad (start >> 28) != (p->rdev->uvd.gpu_addr >> 28)) { 633 1.2 riastrad DRM_ERROR("msg/fb buffer %"PRIX64"-%"PRIX64" out of 256MB segment!\n", 634 1.1 riastrad start, end); 635 1.1 riastrad return -EINVAL; 636 1.1 riastrad } 637 1.1 riastrad 638 1.1 riastrad if (cmd == 0) { 639 1.1 riastrad if (*has_msg_cmd) { 640 1.1 riastrad DRM_ERROR("More than one message in a UVD-IB!\n"); 641 1.1 riastrad return -EINVAL; 642 1.1 riastrad } 643 1.1 riastrad *has_msg_cmd = true; 644 1.1 riastrad r = radeon_uvd_cs_msg(p, reloc->robj, offset, buf_sizes); 645 1.1 riastrad if (r) 646 1.1 riastrad return r; 647 1.1 riastrad } else if (!*has_msg_cmd) { 648 1.1 riastrad DRM_ERROR("Message needed before other commands are send!\n"); 649 1.1 riastrad return -EINVAL; 650 1.1 riastrad } 651 1.1 riastrad 652 1.1 riastrad return 0; 653 1.1 riastrad } 654 1.1 riastrad 655 1.1 riastrad static int radeon_uvd_cs_reg(struct radeon_cs_parser *p, 656 1.1 riastrad struct radeon_cs_packet *pkt, 657 1.1 riastrad int *data0, int *data1, 658 1.1 riastrad unsigned buf_sizes[], 659 1.1 riastrad bool *has_msg_cmd) 660 1.1 riastrad { 661 1.1 riastrad int i, r; 662 1.1 riastrad 663 1.1 riastrad p->idx++; 664 1.1 riastrad for (i = 0; i <= pkt->count; ++i) { 665 1.1 riastrad switch (pkt->reg + i*4) { 666 1.1 riastrad case UVD_GPCOM_VCPU_DATA0: 667 1.1 riastrad *data0 = p->idx; 668 1.1 riastrad break; 669 1.1 riastrad case UVD_GPCOM_VCPU_DATA1: 670 1.1 riastrad *data1 = p->idx; 671 1.1 riastrad break; 672 1.1 riastrad case UVD_GPCOM_VCPU_CMD: 673 1.1 riastrad r = radeon_uvd_cs_reloc(p, *data0, *data1, 674 1.1 riastrad buf_sizes, has_msg_cmd); 675 1.1 riastrad if (r) 676 1.1 riastrad return r; 677 1.1 riastrad break; 678 1.1 riastrad case UVD_ENGINE_CNTL: 679 1.7 riastrad case UVD_NO_OP: 680 1.1 riastrad break; 681 1.1 riastrad default: 682 1.1 riastrad DRM_ERROR("Invalid reg 0x%X!\n", 683 1.1 riastrad pkt->reg + i*4); 684 1.1 riastrad return -EINVAL; 685 1.1 riastrad } 686 1.1 riastrad p->idx++; 687 1.1 riastrad } 688 1.1 riastrad return 0; 689 1.1 riastrad } 690 1.1 riastrad 691 1.1 riastrad int radeon_uvd_cs_parse(struct radeon_cs_parser *p) 692 1.1 riastrad { 693 1.1 riastrad struct radeon_cs_packet pkt; 694 1.1 riastrad int r, data0 = 0, data1 = 0; 695 1.1 riastrad 696 1.1 riastrad /* does the IB has a msg command */ 697 1.1 riastrad bool has_msg_cmd = false; 698 1.1 riastrad 699 1.1 riastrad /* minimum buffer sizes */ 700 1.1 riastrad unsigned buf_sizes[] = { 701 1.1 riastrad [0x00000000] = 2048, 702 1.1 riastrad [0x00000001] = 32 * 1024 * 1024, 703 1.1 riastrad [0x00000002] = 2048 * 1152 * 3, 704 1.1 riastrad [0x00000003] = 2048, 705 1.1 riastrad }; 706 1.1 riastrad 707 1.3 riastrad if (p->chunk_ib->length_dw % 16) { 708 1.1 riastrad DRM_ERROR("UVD IB length (%d) not 16 dwords aligned!\n", 709 1.3 riastrad p->chunk_ib->length_dw); 710 1.1 riastrad return -EINVAL; 711 1.1 riastrad } 712 1.1 riastrad 713 1.3 riastrad if (p->chunk_relocs == NULL) { 714 1.1 riastrad DRM_ERROR("No relocation chunk !\n"); 715 1.1 riastrad return -EINVAL; 716 1.1 riastrad } 717 1.1 riastrad 718 1.1 riastrad 719 1.1 riastrad do { 720 1.1 riastrad r = radeon_cs_packet_parse(p, &pkt, p->idx); 721 1.1 riastrad if (r) 722 1.1 riastrad return r; 723 1.1 riastrad switch (pkt.type) { 724 1.1 riastrad case RADEON_PACKET_TYPE0: 725 1.1 riastrad r = radeon_uvd_cs_reg(p, &pkt, &data0, &data1, 726 1.1 riastrad buf_sizes, &has_msg_cmd); 727 1.1 riastrad if (r) 728 1.1 riastrad return r; 729 1.1 riastrad break; 730 1.1 riastrad case RADEON_PACKET_TYPE2: 731 1.1 riastrad p->idx += pkt.count + 2; 732 1.1 riastrad break; 733 1.1 riastrad default: 734 1.1 riastrad DRM_ERROR("Unknown packet type %d !\n", pkt.type); 735 1.1 riastrad return -EINVAL; 736 1.1 riastrad } 737 1.3 riastrad } while (p->idx < p->chunk_ib->length_dw); 738 1.1 riastrad 739 1.1 riastrad if (!has_msg_cmd) { 740 1.1 riastrad DRM_ERROR("UVD-IBs need a msg command!\n"); 741 1.1 riastrad return -EINVAL; 742 1.1 riastrad } 743 1.1 riastrad 744 1.1 riastrad return 0; 745 1.1 riastrad } 746 1.1 riastrad 747 1.1 riastrad static int radeon_uvd_send_msg(struct radeon_device *rdev, 748 1.3 riastrad int ring, uint64_t addr, 749 1.1 riastrad struct radeon_fence **fence) 750 1.1 riastrad { 751 1.1 riastrad struct radeon_ib ib; 752 1.1 riastrad int i, r; 753 1.1 riastrad 754 1.3 riastrad r = radeon_ib_get(rdev, ring, &ib, NULL, 64); 755 1.1 riastrad if (r) 756 1.1 riastrad return r; 757 1.1 riastrad 758 1.1 riastrad ib.ptr[0] = PACKET0(UVD_GPCOM_VCPU_DATA0, 0); 759 1.1 riastrad ib.ptr[1] = addr; 760 1.1 riastrad ib.ptr[2] = PACKET0(UVD_GPCOM_VCPU_DATA1, 0); 761 1.1 riastrad ib.ptr[3] = addr >> 32; 762 1.1 riastrad ib.ptr[4] = PACKET0(UVD_GPCOM_VCPU_CMD, 0); 763 1.1 riastrad ib.ptr[5] = 0; 764 1.7 riastrad for (i = 6; i < 16; i += 2) { 765 1.7 riastrad ib.ptr[i] = PACKET0(UVD_NO_OP, 0); 766 1.7 riastrad ib.ptr[i+1] = 0; 767 1.7 riastrad } 768 1.1 riastrad ib.length_dw = 16; 769 1.1 riastrad 770 1.3 riastrad r = radeon_ib_schedule(rdev, &ib, NULL, false); 771 1.1 riastrad 772 1.1 riastrad if (fence) 773 1.1 riastrad *fence = radeon_fence_ref(ib.fence); 774 1.1 riastrad 775 1.1 riastrad radeon_ib_free(rdev, &ib); 776 1.1 riastrad return r; 777 1.1 riastrad } 778 1.1 riastrad 779 1.7 riastrad /* 780 1.7 riastrad * multiple fence commands without any stream commands in between can 781 1.7 riastrad * crash the vcpu so just try to emmit a dummy create/destroy msg to 782 1.7 riastrad * avoid this 783 1.7 riastrad */ 784 1.1 riastrad int radeon_uvd_get_create_msg(struct radeon_device *rdev, int ring, 785 1.1 riastrad uint32_t handle, struct radeon_fence **fence) 786 1.1 riastrad { 787 1.3 riastrad /* we use the last page of the vcpu bo for the UVD message */ 788 1.3 riastrad uint64_t offs = radeon_bo_size(rdev->uvd.vcpu_bo) - 789 1.3 riastrad RADEON_GPU_PAGE_SIZE; 790 1.3 riastrad 791 1.5 riastrad uint32_t *msg = rdev->uvd.cpu_addr + offs; 792 1.3 riastrad uint64_t addr = rdev->uvd.gpu_addr + offs; 793 1.3 riastrad 794 1.1 riastrad int r, i; 795 1.1 riastrad 796 1.3 riastrad r = radeon_bo_reserve(rdev->uvd.vcpu_bo, true); 797 1.1 riastrad if (r) 798 1.1 riastrad return r; 799 1.1 riastrad 800 1.1 riastrad /* stitch together an UVD create msg */ 801 1.1 riastrad msg[0] = cpu_to_le32(0x00000de4); 802 1.1 riastrad msg[1] = cpu_to_le32(0x00000000); 803 1.1 riastrad msg[2] = cpu_to_le32(handle); 804 1.1 riastrad msg[3] = cpu_to_le32(0x00000000); 805 1.1 riastrad msg[4] = cpu_to_le32(0x00000000); 806 1.1 riastrad msg[5] = cpu_to_le32(0x00000000); 807 1.1 riastrad msg[6] = cpu_to_le32(0x00000000); 808 1.1 riastrad msg[7] = cpu_to_le32(0x00000780); 809 1.1 riastrad msg[8] = cpu_to_le32(0x00000440); 810 1.1 riastrad msg[9] = cpu_to_le32(0x00000000); 811 1.1 riastrad msg[10] = cpu_to_le32(0x01b37000); 812 1.1 riastrad for (i = 11; i < 1024; ++i) 813 1.1 riastrad msg[i] = cpu_to_le32(0x0); 814 1.1 riastrad 815 1.3 riastrad r = radeon_uvd_send_msg(rdev, ring, addr, fence); 816 1.3 riastrad radeon_bo_unreserve(rdev->uvd.vcpu_bo); 817 1.3 riastrad return r; 818 1.1 riastrad } 819 1.1 riastrad 820 1.1 riastrad int radeon_uvd_get_destroy_msg(struct radeon_device *rdev, int ring, 821 1.1 riastrad uint32_t handle, struct radeon_fence **fence) 822 1.1 riastrad { 823 1.3 riastrad /* we use the last page of the vcpu bo for the UVD message */ 824 1.3 riastrad uint64_t offs = radeon_bo_size(rdev->uvd.vcpu_bo) - 825 1.3 riastrad RADEON_GPU_PAGE_SIZE; 826 1.3 riastrad 827 1.5 riastrad uint32_t *msg = rdev->uvd.cpu_addr + offs; 828 1.3 riastrad uint64_t addr = rdev->uvd.gpu_addr + offs; 829 1.3 riastrad 830 1.1 riastrad int r, i; 831 1.1 riastrad 832 1.3 riastrad r = radeon_bo_reserve(rdev->uvd.vcpu_bo, true); 833 1.1 riastrad if (r) 834 1.1 riastrad return r; 835 1.1 riastrad 836 1.1 riastrad /* stitch together an UVD destroy msg */ 837 1.1 riastrad msg[0] = cpu_to_le32(0x00000de4); 838 1.1 riastrad msg[1] = cpu_to_le32(0x00000002); 839 1.1 riastrad msg[2] = cpu_to_le32(handle); 840 1.1 riastrad msg[3] = cpu_to_le32(0x00000000); 841 1.1 riastrad for (i = 4; i < 1024; ++i) 842 1.1 riastrad msg[i] = cpu_to_le32(0x0); 843 1.1 riastrad 844 1.3 riastrad r = radeon_uvd_send_msg(rdev, ring, addr, fence); 845 1.3 riastrad radeon_bo_unreserve(rdev->uvd.vcpu_bo); 846 1.3 riastrad return r; 847 1.1 riastrad } 848 1.1 riastrad 849 1.1 riastrad /** 850 1.1 riastrad * radeon_uvd_count_handles - count number of open streams 851 1.1 riastrad * 852 1.1 riastrad * @rdev: radeon_device pointer 853 1.1 riastrad * @sd: number of SD streams 854 1.1 riastrad * @hd: number of HD streams 855 1.1 riastrad * 856 1.1 riastrad * Count the number of open SD/HD streams as a hint for power mangement 857 1.1 riastrad */ 858 1.1 riastrad static void radeon_uvd_count_handles(struct radeon_device *rdev, 859 1.1 riastrad unsigned *sd, unsigned *hd) 860 1.1 riastrad { 861 1.1 riastrad unsigned i; 862 1.1 riastrad 863 1.1 riastrad *sd = 0; 864 1.1 riastrad *hd = 0; 865 1.1 riastrad 866 1.7 riastrad for (i = 0; i < rdev->uvd.max_handles; ++i) { 867 1.1 riastrad if (!atomic_read(&rdev->uvd.handles[i])) 868 1.1 riastrad continue; 869 1.1 riastrad 870 1.1 riastrad if (rdev->uvd.img_size[i] >= 720*576) 871 1.1 riastrad ++(*hd); 872 1.1 riastrad else 873 1.1 riastrad ++(*sd); 874 1.1 riastrad } 875 1.1 riastrad } 876 1.1 riastrad 877 1.1 riastrad static void radeon_uvd_idle_work_handler(struct work_struct *work) 878 1.1 riastrad { 879 1.1 riastrad struct radeon_device *rdev = 880 1.1 riastrad container_of(work, struct radeon_device, uvd.idle_work.work); 881 1.1 riastrad 882 1.1 riastrad if (radeon_fence_count_emitted(rdev, R600_RING_TYPE_UVD_INDEX) == 0) { 883 1.1 riastrad if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) { 884 1.1 riastrad radeon_uvd_count_handles(rdev, &rdev->pm.dpm.sd, 885 1.1 riastrad &rdev->pm.dpm.hd); 886 1.1 riastrad radeon_dpm_enable_uvd(rdev, false); 887 1.1 riastrad } else { 888 1.1 riastrad radeon_set_uvd_clocks(rdev, 0, 0); 889 1.1 riastrad } 890 1.1 riastrad } else { 891 1.1 riastrad schedule_delayed_work(&rdev->uvd.idle_work, 892 1.1 riastrad msecs_to_jiffies(UVD_IDLE_TIMEOUT_MS)); 893 1.1 riastrad } 894 1.1 riastrad } 895 1.1 riastrad 896 1.1 riastrad void radeon_uvd_note_usage(struct radeon_device *rdev) 897 1.1 riastrad { 898 1.1 riastrad bool streams_changed = false; 899 1.1 riastrad bool set_clocks = !cancel_delayed_work_sync(&rdev->uvd.idle_work); 900 1.1 riastrad set_clocks &= schedule_delayed_work(&rdev->uvd.idle_work, 901 1.1 riastrad msecs_to_jiffies(UVD_IDLE_TIMEOUT_MS)); 902 1.1 riastrad 903 1.1 riastrad if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) { 904 1.1 riastrad unsigned hd = 0, sd = 0; 905 1.1 riastrad radeon_uvd_count_handles(rdev, &sd, &hd); 906 1.1 riastrad if ((rdev->pm.dpm.sd != sd) || 907 1.1 riastrad (rdev->pm.dpm.hd != hd)) { 908 1.1 riastrad rdev->pm.dpm.sd = sd; 909 1.1 riastrad rdev->pm.dpm.hd = hd; 910 1.3 riastrad /* disable this for now */ 911 1.3 riastrad /*streams_changed = true;*/ 912 1.1 riastrad } 913 1.1 riastrad } 914 1.1 riastrad 915 1.1 riastrad if (set_clocks || streams_changed) { 916 1.1 riastrad if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) { 917 1.1 riastrad radeon_dpm_enable_uvd(rdev, true); 918 1.1 riastrad } else { 919 1.1 riastrad radeon_set_uvd_clocks(rdev, 53300, 40000); 920 1.1 riastrad } 921 1.1 riastrad } 922 1.1 riastrad } 923 1.1 riastrad 924 1.1 riastrad static unsigned radeon_uvd_calc_upll_post_div(unsigned vco_freq, 925 1.1 riastrad unsigned target_freq, 926 1.1 riastrad unsigned pd_min, 927 1.1 riastrad unsigned pd_even) 928 1.1 riastrad { 929 1.1 riastrad unsigned post_div = vco_freq / target_freq; 930 1.1 riastrad 931 1.1 riastrad /* adjust to post divider minimum value */ 932 1.1 riastrad if (post_div < pd_min) 933 1.1 riastrad post_div = pd_min; 934 1.1 riastrad 935 1.1 riastrad /* we alway need a frequency less than or equal the target */ 936 1.1 riastrad if ((vco_freq / post_div) > target_freq) 937 1.1 riastrad post_div += 1; 938 1.1 riastrad 939 1.1 riastrad /* post dividers above a certain value must be even */ 940 1.1 riastrad if (post_div > pd_even && post_div % 2) 941 1.1 riastrad post_div += 1; 942 1.1 riastrad 943 1.1 riastrad return post_div; 944 1.1 riastrad } 945 1.1 riastrad 946 1.1 riastrad /** 947 1.1 riastrad * radeon_uvd_calc_upll_dividers - calc UPLL clock dividers 948 1.1 riastrad * 949 1.1 riastrad * @rdev: radeon_device pointer 950 1.1 riastrad * @vclk: wanted VCLK 951 1.1 riastrad * @dclk: wanted DCLK 952 1.1 riastrad * @vco_min: minimum VCO frequency 953 1.1 riastrad * @vco_max: maximum VCO frequency 954 1.1 riastrad * @fb_factor: factor to multiply vco freq with 955 1.1 riastrad * @fb_mask: limit and bitmask for feedback divider 956 1.1 riastrad * @pd_min: post divider minimum 957 1.1 riastrad * @pd_max: post divider maximum 958 1.1 riastrad * @pd_even: post divider must be even above this value 959 1.1 riastrad * @optimal_fb_div: resulting feedback divider 960 1.1 riastrad * @optimal_vclk_div: resulting vclk post divider 961 1.1 riastrad * @optimal_dclk_div: resulting dclk post divider 962 1.1 riastrad * 963 1.1 riastrad * Calculate dividers for UVDs UPLL (R6xx-SI, except APUs). 964 1.1 riastrad * Returns zero on success -EINVAL on error. 965 1.1 riastrad */ 966 1.1 riastrad int radeon_uvd_calc_upll_dividers(struct radeon_device *rdev, 967 1.1 riastrad unsigned vclk, unsigned dclk, 968 1.1 riastrad unsigned vco_min, unsigned vco_max, 969 1.1 riastrad unsigned fb_factor, unsigned fb_mask, 970 1.1 riastrad unsigned pd_min, unsigned pd_max, 971 1.1 riastrad unsigned pd_even, 972 1.1 riastrad unsigned *optimal_fb_div, 973 1.1 riastrad unsigned *optimal_vclk_div, 974 1.1 riastrad unsigned *optimal_dclk_div) 975 1.1 riastrad { 976 1.1 riastrad unsigned vco_freq, ref_freq = rdev->clock.spll.reference_freq; 977 1.1 riastrad 978 1.1 riastrad /* start off with something large */ 979 1.1 riastrad unsigned optimal_score = ~0; 980 1.1 riastrad 981 1.1 riastrad /* loop through vco from low to high */ 982 1.1 riastrad vco_min = max(max(vco_min, vclk), dclk); 983 1.1 riastrad for (vco_freq = vco_min; vco_freq <= vco_max; vco_freq += 100) { 984 1.1 riastrad 985 1.1 riastrad uint64_t fb_div = (uint64_t)vco_freq * fb_factor; 986 1.1 riastrad unsigned vclk_div, dclk_div, score; 987 1.1 riastrad 988 1.1 riastrad do_div(fb_div, ref_freq); 989 1.1 riastrad 990 1.1 riastrad /* fb div out of range ? */ 991 1.1 riastrad if (fb_div > fb_mask) 992 1.1 riastrad break; /* it can oly get worse */ 993 1.1 riastrad 994 1.1 riastrad fb_div &= fb_mask; 995 1.1 riastrad 996 1.1 riastrad /* calc vclk divider with current vco freq */ 997 1.1 riastrad vclk_div = radeon_uvd_calc_upll_post_div(vco_freq, vclk, 998 1.1 riastrad pd_min, pd_even); 999 1.1 riastrad if (vclk_div > pd_max) 1000 1.1 riastrad break; /* vco is too big, it has to stop */ 1001 1.1 riastrad 1002 1.1 riastrad /* calc dclk divider with current vco freq */ 1003 1.1 riastrad dclk_div = radeon_uvd_calc_upll_post_div(vco_freq, dclk, 1004 1.1 riastrad pd_min, pd_even); 1005 1.3 riastrad if (dclk_div > pd_max) 1006 1.1 riastrad break; /* vco is too big, it has to stop */ 1007 1.1 riastrad 1008 1.1 riastrad /* calc score with current vco freq */ 1009 1.1 riastrad score = vclk - (vco_freq / vclk_div) + dclk - (vco_freq / dclk_div); 1010 1.1 riastrad 1011 1.1 riastrad /* determine if this vco setting is better than current optimal settings */ 1012 1.1 riastrad if (score < optimal_score) { 1013 1.1 riastrad *optimal_fb_div = fb_div; 1014 1.1 riastrad *optimal_vclk_div = vclk_div; 1015 1.1 riastrad *optimal_dclk_div = dclk_div; 1016 1.1 riastrad optimal_score = score; 1017 1.1 riastrad if (optimal_score == 0) 1018 1.1 riastrad break; /* it can't get better than this */ 1019 1.1 riastrad } 1020 1.1 riastrad } 1021 1.1 riastrad 1022 1.1 riastrad /* did we found a valid setup ? */ 1023 1.1 riastrad if (optimal_score == ~0) 1024 1.1 riastrad return -EINVAL; 1025 1.1 riastrad 1026 1.1 riastrad return 0; 1027 1.1 riastrad } 1028 1.1 riastrad 1029 1.1 riastrad int radeon_uvd_send_upll_ctlreq(struct radeon_device *rdev, 1030 1.1 riastrad unsigned cg_upll_func_cntl) 1031 1.1 riastrad { 1032 1.1 riastrad unsigned i; 1033 1.1 riastrad 1034 1.1 riastrad /* make sure UPLL_CTLREQ is deasserted */ 1035 1.1 riastrad WREG32_P(cg_upll_func_cntl, 0, ~UPLL_CTLREQ_MASK); 1036 1.1 riastrad 1037 1.1 riastrad mdelay(10); 1038 1.1 riastrad 1039 1.1 riastrad /* assert UPLL_CTLREQ */ 1040 1.1 riastrad WREG32_P(cg_upll_func_cntl, UPLL_CTLREQ_MASK, ~UPLL_CTLREQ_MASK); 1041 1.1 riastrad 1042 1.1 riastrad /* wait for CTLACK and CTLACK2 to get asserted */ 1043 1.1 riastrad for (i = 0; i < 100; ++i) { 1044 1.1 riastrad uint32_t mask = UPLL_CTLACK_MASK | UPLL_CTLACK2_MASK; 1045 1.1 riastrad if ((RREG32(cg_upll_func_cntl) & mask) == mask) 1046 1.1 riastrad break; 1047 1.1 riastrad mdelay(10); 1048 1.1 riastrad } 1049 1.1 riastrad 1050 1.1 riastrad /* deassert UPLL_CTLREQ */ 1051 1.1 riastrad WREG32_P(cg_upll_func_cntl, 0, ~UPLL_CTLREQ_MASK); 1052 1.1 riastrad 1053 1.1 riastrad if (i == 100) { 1054 1.1 riastrad DRM_ERROR("Timeout setting UVD clocks!\n"); 1055 1.1 riastrad return -ETIMEDOUT; 1056 1.1 riastrad } 1057 1.1 riastrad 1058 1.1 riastrad return 0; 1059 1.1 riastrad } 1060