Home | History | Annotate | Line # | Download | only in radeon
      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