blob: 1b3a91bf1a9dba3f2f12aa91650ceb9cf7edd7f0 [file] [log] [blame]
Christian Königf2ba57b2013-04-08 12:41:29 +02001/*
2 * Copyright 2011 Advanced Micro Devices, Inc.
3 * All Rights Reserved.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the
7 * "Software"), to deal in the Software without restriction, including
8 * without limitation the rights to use, copy, modify, merge, publish,
9 * distribute, sub license, and/or sell copies of the Software, and to
10 * permit persons to whom the Software is furnished to do so, subject to
11 * the following conditions:
12 *
13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
16 * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
17 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
18 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
19 * USE OR OTHER DEALINGS IN THE SOFTWARE.
20 *
21 * The above copyright notice and this permission notice (including the
22 * next paragraph) shall be included in all copies or substantial portions
23 * of the Software.
24 *
25 */
26/*
27 * Authors:
28 * Christian König <deathsimple@vodafone.de>
29 */
30
31#include <linux/firmware.h>
32#include <linux/module.h>
33#include <drm/drmP.h>
34#include <drm/drm.h>
35
36#include "radeon.h"
37#include "r600d.h"
38
Christian König55b51c82013-04-18 15:25:59 +020039/* 1 second timeout */
40#define UVD_IDLE_TIMEOUT_MS 1000
41
Christian Königf2ba57b2013-04-08 12:41:29 +020042/* Firmware Names */
43#define FIRMWARE_RV710 "radeon/RV710_uvd.bin"
44#define FIRMWARE_CYPRESS "radeon/CYPRESS_uvd.bin"
45#define FIRMWARE_SUMO "radeon/SUMO_uvd.bin"
46#define FIRMWARE_TAHITI "radeon/TAHITI_uvd.bin"
47
48MODULE_FIRMWARE(FIRMWARE_RV710);
49MODULE_FIRMWARE(FIRMWARE_CYPRESS);
50MODULE_FIRMWARE(FIRMWARE_SUMO);
51MODULE_FIRMWARE(FIRMWARE_TAHITI);
52
Christian König55b51c82013-04-18 15:25:59 +020053static void radeon_uvd_idle_work_handler(struct work_struct *work);
54
Christian Königf2ba57b2013-04-08 12:41:29 +020055int radeon_uvd_init(struct radeon_device *rdev)
56{
57 struct platform_device *pdev;
Christian König8ecbcde2013-07-12 10:18:09 -040058 const struct firmware *fw;
Christian Königf2ba57b2013-04-08 12:41:29 +020059 unsigned long bo_size;
60 const char *fw_name;
61 int i, r;
62
Christian König55b51c82013-04-18 15:25:59 +020063 INIT_DELAYED_WORK(&rdev->uvd.idle_work, radeon_uvd_idle_work_handler);
64
Christian Königf2ba57b2013-04-08 12:41:29 +020065 pdev = platform_device_register_simple("radeon_uvd", 0, NULL, 0);
66 r = IS_ERR(pdev);
67 if (r) {
68 dev_err(rdev->dev, "radeon_uvd: Failed to register firmware\n");
69 return -EINVAL;
70 }
71
72 switch (rdev->family) {
73 case CHIP_RV710:
74 case CHIP_RV730:
75 case CHIP_RV740:
76 fw_name = FIRMWARE_RV710;
77 break;
78
79 case CHIP_CYPRESS:
80 case CHIP_HEMLOCK:
81 case CHIP_JUNIPER:
82 case CHIP_REDWOOD:
83 case CHIP_CEDAR:
84 fw_name = FIRMWARE_CYPRESS;
85 break;
86
87 case CHIP_SUMO:
88 case CHIP_SUMO2:
89 case CHIP_PALM:
90 case CHIP_CAYMAN:
91 case CHIP_BARTS:
92 case CHIP_TURKS:
93 case CHIP_CAICOS:
94 fw_name = FIRMWARE_SUMO;
95 break;
96
97 case CHIP_TAHITI:
98 case CHIP_VERDE:
99 case CHIP_PITCAIRN:
100 case CHIP_ARUBA:
101 fw_name = FIRMWARE_TAHITI;
102 break;
103
104 default:
105 return -EINVAL;
106 }
107
Christian König8ecbcde2013-07-12 10:18:09 -0400108 r = request_firmware(&fw, fw_name, &pdev->dev);
Christian Königf2ba57b2013-04-08 12:41:29 +0200109 if (r) {
110 dev_err(rdev->dev, "radeon_uvd: Can't load firmware \"%s\"\n",
111 fw_name);
112 platform_device_unregister(pdev);
113 return r;
114 }
115
116 platform_device_unregister(pdev);
117
Christian König8ecbcde2013-07-12 10:18:09 -0400118 bo_size = RADEON_GPU_PAGE_ALIGN(fw->size + 8) +
Christian Königf2ba57b2013-04-08 12:41:29 +0200119 RADEON_UVD_STACK_SIZE + RADEON_UVD_HEAP_SIZE;
120 r = radeon_bo_create(rdev, bo_size, PAGE_SIZE, true,
121 RADEON_GEM_DOMAIN_VRAM, NULL, &rdev->uvd.vcpu_bo);
122 if (r) {
123 dev_err(rdev->dev, "(%d) failed to allocate UVD bo\n", r);
124 return r;
125 }
126
Christian Königf2ba57b2013-04-08 12:41:29 +0200127 r = radeon_bo_reserve(rdev->uvd.vcpu_bo, false);
128 if (r) {
129 radeon_bo_unref(&rdev->uvd.vcpu_bo);
130 dev_err(rdev->dev, "(%d) failed to reserve UVD bo\n", r);
131 return r;
132 }
133
134 r = radeon_bo_pin(rdev->uvd.vcpu_bo, RADEON_GEM_DOMAIN_VRAM,
135 &rdev->uvd.gpu_addr);
136 if (r) {
137 radeon_bo_unreserve(rdev->uvd.vcpu_bo);
138 radeon_bo_unref(&rdev->uvd.vcpu_bo);
139 dev_err(rdev->dev, "(%d) UVD bo pin failed\n", r);
140 return r;
141 }
142
143 r = radeon_bo_kmap(rdev->uvd.vcpu_bo, &rdev->uvd.cpu_addr);
144 if (r) {
145 dev_err(rdev->dev, "(%d) UVD map failed\n", r);
146 return r;
147 }
148
149 radeon_bo_unreserve(rdev->uvd.vcpu_bo);
150
Christian König8ecbcde2013-07-12 10:18:09 -0400151 rdev->uvd.fw_size = fw->size;
152 memset(rdev->uvd.cpu_addr, 0, bo_size);
153 memcpy(rdev->uvd.cpu_addr, fw->data, fw->size);
154
155 release_firmware(fw);
156
157 for (i = 0; i < RADEON_MAX_UVD_HANDLES; ++i) {
158 atomic_set(&rdev->uvd.handles[i], 0);
159 rdev->uvd.filp[i] = NULL;
160 }
161
162 return 0;
163}
164
165void radeon_uvd_fini(struct radeon_device *rdev)
166{
167 int r;
168
169 if (rdev->uvd.vcpu_bo == NULL)
170 return;
171
172 r = radeon_bo_reserve(rdev->uvd.vcpu_bo, false);
173 if (!r) {
174 radeon_bo_kunmap(rdev->uvd.vcpu_bo);
175 radeon_bo_unpin(rdev->uvd.vcpu_bo);
176 radeon_bo_unreserve(rdev->uvd.vcpu_bo);
177 }
178
179 radeon_bo_unref(&rdev->uvd.vcpu_bo);
180}
181
182int radeon_uvd_suspend(struct radeon_device *rdev)
183{
184 unsigned size;
185
186 if (rdev->uvd.vcpu_bo == NULL)
187 return 0;
188
189 size = radeon_bo_size(rdev->uvd.vcpu_bo);
190 rdev->uvd.saved_bo = kmalloc(size, GFP_KERNEL);
191 memcpy(rdev->uvd.saved_bo, rdev->uvd.cpu_addr, size);
192
193 return 0;
194}
195
196int radeon_uvd_resume(struct radeon_device *rdev)
197{
198 if (rdev->uvd.vcpu_bo == NULL)
199 return -EINVAL;
200
201 if (rdev->uvd.saved_bo != NULL) {
202 unsigned size = radeon_bo_size(rdev->uvd.vcpu_bo);
203 memcpy(rdev->uvd.cpu_addr, rdev->uvd.saved_bo, size);
204 kfree(rdev->uvd.saved_bo);
205 rdev->uvd.saved_bo = NULL;
206 }
207
Christian Königf2ba57b2013-04-08 12:41:29 +0200208 return 0;
209}
210
211void radeon_uvd_force_into_uvd_segment(struct radeon_bo *rbo)
212{
213 rbo->placement.fpfn = 0 >> PAGE_SHIFT;
214 rbo->placement.lpfn = (256 * 1024 * 1024) >> PAGE_SHIFT;
215}
216
217void radeon_uvd_free_handles(struct radeon_device *rdev, struct drm_file *filp)
218{
219 int i, r;
220 for (i = 0; i < RADEON_MAX_UVD_HANDLES; ++i) {
221 if (rdev->uvd.filp[i] == filp) {
222 uint32_t handle = atomic_read(&rdev->uvd.handles[i]);
223 struct radeon_fence *fence;
224
225 r = radeon_uvd_get_destroy_msg(rdev,
226 R600_RING_TYPE_UVD_INDEX, handle, &fence);
227 if (r) {
228 DRM_ERROR("Error destroying UVD (%d)!\n", r);
229 continue;
230 }
231
232 radeon_fence_wait(fence, false);
233 radeon_fence_unref(&fence);
234
235 rdev->uvd.filp[i] = NULL;
236 atomic_set(&rdev->uvd.handles[i], 0);
237 }
238 }
239}
240
241static int radeon_uvd_cs_msg_decode(uint32_t *msg, unsigned buf_sizes[])
242{
243 unsigned stream_type = msg[4];
244 unsigned width = msg[6];
245 unsigned height = msg[7];
246 unsigned dpb_size = msg[9];
247 unsigned pitch = msg[28];
248
249 unsigned width_in_mb = width / 16;
250 unsigned height_in_mb = ALIGN(height / 16, 2);
251
252 unsigned image_size, tmp, min_dpb_size;
253
254 image_size = width * height;
255 image_size += image_size / 2;
256 image_size = ALIGN(image_size, 1024);
257
258 switch (stream_type) {
259 case 0: /* H264 */
260
261 /* reference picture buffer */
262 min_dpb_size = image_size * 17;
263
264 /* macroblock context buffer */
265 min_dpb_size += width_in_mb * height_in_mb * 17 * 192;
266
267 /* IT surface buffer */
268 min_dpb_size += width_in_mb * height_in_mb * 32;
269 break;
270
271 case 1: /* VC1 */
272
273 /* reference picture buffer */
274 min_dpb_size = image_size * 3;
275
276 /* CONTEXT_BUFFER */
277 min_dpb_size += width_in_mb * height_in_mb * 128;
278
279 /* IT surface buffer */
280 min_dpb_size += width_in_mb * 64;
281
282 /* DB surface buffer */
283 min_dpb_size += width_in_mb * 128;
284
285 /* BP */
286 tmp = max(width_in_mb, height_in_mb);
287 min_dpb_size += ALIGN(tmp * 7 * 16, 64);
288 break;
289
290 case 3: /* MPEG2 */
291
292 /* reference picture buffer */
293 min_dpb_size = image_size * 3;
294 break;
295
296 case 4: /* MPEG4 */
297
298 /* reference picture buffer */
299 min_dpb_size = image_size * 3;
300
301 /* CM */
302 min_dpb_size += width_in_mb * height_in_mb * 64;
303
304 /* IT surface buffer */
305 min_dpb_size += ALIGN(width_in_mb * height_in_mb * 32, 64);
306 break;
307
308 default:
309 DRM_ERROR("UVD codec not handled %d!\n", stream_type);
310 return -EINVAL;
311 }
312
313 if (width > pitch) {
314 DRM_ERROR("Invalid UVD decoding target pitch!\n");
315 return -EINVAL;
316 }
317
318 if (dpb_size < min_dpb_size) {
319 DRM_ERROR("Invalid dpb_size in UVD message (%d / %d)!\n",
320 dpb_size, min_dpb_size);
321 return -EINVAL;
322 }
323
324 buf_sizes[0x1] = dpb_size;
325 buf_sizes[0x2] = image_size;
326 return 0;
327}
328
329static int radeon_uvd_cs_msg(struct radeon_cs_parser *p, struct radeon_bo *bo,
330 unsigned offset, unsigned buf_sizes[])
331{
332 int32_t *msg, msg_type, handle;
333 void *ptr;
334
335 int i, r;
336
337 if (offset & 0x3F) {
338 DRM_ERROR("UVD messages must be 64 byte aligned!\n");
339 return -EINVAL;
340 }
341
342 r = radeon_bo_kmap(bo, &ptr);
343 if (r)
344 return r;
345
346 msg = ptr + offset;
347
348 msg_type = msg[1];
349 handle = msg[2];
350
351 if (handle == 0) {
352 DRM_ERROR("Invalid UVD handle!\n");
353 return -EINVAL;
354 }
355
356 if (msg_type == 1) {
357 /* it's a decode msg, calc buffer sizes */
358 r = radeon_uvd_cs_msg_decode(msg, buf_sizes);
359 radeon_bo_kunmap(bo);
360 if (r)
361 return r;
362
363 } else if (msg_type == 2) {
364 /* it's a destroy msg, free the handle */
365 for (i = 0; i < RADEON_MAX_UVD_HANDLES; ++i)
366 atomic_cmpxchg(&p->rdev->uvd.handles[i], handle, 0);
367 radeon_bo_kunmap(bo);
368 return 0;
369 } else {
370 /* it's a create msg, no special handling needed */
371 radeon_bo_kunmap(bo);
372 }
373
374 /* create or decode, validate the handle */
375 for (i = 0; i < RADEON_MAX_UVD_HANDLES; ++i) {
376 if (atomic_read(&p->rdev->uvd.handles[i]) == handle)
377 return 0;
378 }
379
380 /* handle not found try to alloc a new one */
381 for (i = 0; i < RADEON_MAX_UVD_HANDLES; ++i) {
382 if (!atomic_cmpxchg(&p->rdev->uvd.handles[i], 0, handle)) {
383 p->rdev->uvd.filp[i] = p->filp;
384 return 0;
385 }
386 }
387
388 DRM_ERROR("No more free UVD handles!\n");
389 return -EINVAL;
390}
391
392static int radeon_uvd_cs_reloc(struct radeon_cs_parser *p,
393 int data0, int data1,
394 unsigned buf_sizes[])
395{
396 struct radeon_cs_chunk *relocs_chunk;
397 struct radeon_cs_reloc *reloc;
398 unsigned idx, cmd, offset;
399 uint64_t start, end;
400 int r;
401
402 relocs_chunk = &p->chunks[p->chunk_relocs_idx];
403 offset = radeon_get_ib_value(p, data0);
404 idx = radeon_get_ib_value(p, data1);
405 if (idx >= relocs_chunk->length_dw) {
406 DRM_ERROR("Relocs at %d after relocations chunk end %d !\n",
407 idx, relocs_chunk->length_dw);
408 return -EINVAL;
409 }
410
411 reloc = p->relocs_ptr[(idx / 4)];
412 start = reloc->lobj.gpu_offset;
413 end = start + radeon_bo_size(reloc->robj);
414 start += offset;
415
416 p->ib.ptr[data0] = start & 0xFFFFFFFF;
417 p->ib.ptr[data1] = start >> 32;
418
419 cmd = radeon_get_ib_value(p, p->idx) >> 1;
420
421 if (cmd < 0x4) {
422 if ((end - start) < buf_sizes[cmd]) {
423 DRM_ERROR("buffer to small (%d / %d)!\n",
424 (unsigned)(end - start), buf_sizes[cmd]);
425 return -EINVAL;
426 }
427
428 } else if (cmd != 0x100) {
429 DRM_ERROR("invalid UVD command %X!\n", cmd);
430 return -EINVAL;
431 }
432
Christian Königa92c7d52013-04-14 12:45:43 +0200433 if ((start >> 28) != (end >> 28)) {
Christian Königf2ba57b2013-04-08 12:41:29 +0200434 DRM_ERROR("reloc %LX-%LX crossing 256MB boundary!\n",
435 start, end);
436 return -EINVAL;
437 }
438
Christian Königa92c7d52013-04-14 12:45:43 +0200439 /* TODO: is this still necessary on NI+ ? */
440 if ((cmd == 0 || cmd == 0x3) &&
441 (start >> 28) != (p->rdev->uvd.gpu_addr >> 28)) {
442 DRM_ERROR("msg/fb buffer %LX-%LX out of 256MB segment!\n",
443 start, end);
444 return -EINVAL;
445 }
446
447 if (cmd == 0) {
448 r = radeon_uvd_cs_msg(p, reloc->robj, offset, buf_sizes);
449 if (r)
450 return r;
451 }
452
Christian Königf2ba57b2013-04-08 12:41:29 +0200453 return 0;
454}
455
456static int radeon_uvd_cs_reg(struct radeon_cs_parser *p,
457 struct radeon_cs_packet *pkt,
458 int *data0, int *data1,
459 unsigned buf_sizes[])
460{
461 int i, r;
462
463 p->idx++;
464 for (i = 0; i <= pkt->count; ++i) {
465 switch (pkt->reg + i*4) {
466 case UVD_GPCOM_VCPU_DATA0:
467 *data0 = p->idx;
468 break;
469 case UVD_GPCOM_VCPU_DATA1:
470 *data1 = p->idx;
471 break;
472 case UVD_GPCOM_VCPU_CMD:
473 r = radeon_uvd_cs_reloc(p, *data0, *data1, buf_sizes);
474 if (r)
475 return r;
476 break;
477 case UVD_ENGINE_CNTL:
478 break;
479 default:
480 DRM_ERROR("Invalid reg 0x%X!\n",
481 pkt->reg + i*4);
482 return -EINVAL;
483 }
484 p->idx++;
485 }
486 return 0;
487}
488
489int radeon_uvd_cs_parse(struct radeon_cs_parser *p)
490{
491 struct radeon_cs_packet pkt;
492 int r, data0 = 0, data1 = 0;
493
494 /* minimum buffer sizes */
495 unsigned buf_sizes[] = {
496 [0x00000000] = 2048,
497 [0x00000001] = 32 * 1024 * 1024,
498 [0x00000002] = 2048 * 1152 * 3,
499 [0x00000003] = 2048,
500 };
501
502 if (p->chunks[p->chunk_ib_idx].length_dw % 16) {
503 DRM_ERROR("UVD IB length (%d) not 16 dwords aligned!\n",
504 p->chunks[p->chunk_ib_idx].length_dw);
505 return -EINVAL;
506 }
507
508 if (p->chunk_relocs_idx == -1) {
509 DRM_ERROR("No relocation chunk !\n");
510 return -EINVAL;
511 }
512
513
514 do {
515 r = radeon_cs_packet_parse(p, &pkt, p->idx);
516 if (r)
517 return r;
518 switch (pkt.type) {
519 case RADEON_PACKET_TYPE0:
520 r = radeon_uvd_cs_reg(p, &pkt, &data0,
521 &data1, buf_sizes);
522 if (r)
523 return r;
524 break;
525 case RADEON_PACKET_TYPE2:
526 p->idx += pkt.count + 2;
527 break;
528 default:
529 DRM_ERROR("Unknown packet type %d !\n", pkt.type);
530 return -EINVAL;
531 }
532 } while (p->idx < p->chunks[p->chunk_ib_idx].length_dw);
533 return 0;
534}
535
536static int radeon_uvd_send_msg(struct radeon_device *rdev,
537 int ring, struct radeon_bo *bo,
538 struct radeon_fence **fence)
539{
540 struct ttm_validate_buffer tv;
541 struct list_head head;
542 struct radeon_ib ib;
543 uint64_t addr;
544 int i, r;
545
546 memset(&tv, 0, sizeof(tv));
547 tv.bo = &bo->tbo;
548
549 INIT_LIST_HEAD(&head);
550 list_add(&tv.head, &head);
551
552 r = ttm_eu_reserve_buffers(&head);
553 if (r)
554 return r;
555
556 radeon_ttm_placement_from_domain(bo, RADEON_GEM_DOMAIN_VRAM);
557 radeon_uvd_force_into_uvd_segment(bo);
558
559 r = ttm_bo_validate(&bo->tbo, &bo->placement, true, false);
560 if (r) {
561 ttm_eu_backoff_reservation(&head);
562 return r;
563 }
564
565 r = radeon_ib_get(rdev, ring, &ib, NULL, 16);
566 if (r) {
567 ttm_eu_backoff_reservation(&head);
568 return r;
569 }
570
571 addr = radeon_bo_gpu_offset(bo);
572 ib.ptr[0] = PACKET0(UVD_GPCOM_VCPU_DATA0, 0);
573 ib.ptr[1] = addr;
574 ib.ptr[2] = PACKET0(UVD_GPCOM_VCPU_DATA1, 0);
575 ib.ptr[3] = addr >> 32;
576 ib.ptr[4] = PACKET0(UVD_GPCOM_VCPU_CMD, 0);
577 ib.ptr[5] = 0;
578 for (i = 6; i < 16; ++i)
579 ib.ptr[i] = PACKET2(0);
580 ib.length_dw = 16;
581
582 r = radeon_ib_schedule(rdev, &ib, NULL);
583 if (r) {
584 ttm_eu_backoff_reservation(&head);
585 return r;
586 }
587 ttm_eu_fence_buffer_objects(&head, ib.fence);
588
589 if (fence)
590 *fence = radeon_fence_ref(ib.fence);
591
592 radeon_ib_free(rdev, &ib);
593 radeon_bo_unref(&bo);
594 return 0;
595}
596
597/* multiple fence commands without any stream commands in between can
598 crash the vcpu so just try to emmit a dummy create/destroy msg to
599 avoid this */
600int radeon_uvd_get_create_msg(struct radeon_device *rdev, int ring,
601 uint32_t handle, struct radeon_fence **fence)
602{
603 struct radeon_bo *bo;
604 uint32_t *msg;
605 int r, i;
606
607 r = radeon_bo_create(rdev, 1024, PAGE_SIZE, true,
608 RADEON_GEM_DOMAIN_VRAM, NULL, &bo);
609 if (r)
610 return r;
611
612 r = radeon_bo_reserve(bo, false);
613 if (r) {
614 radeon_bo_unref(&bo);
615 return r;
616 }
617
618 r = radeon_bo_kmap(bo, (void **)&msg);
619 if (r) {
620 radeon_bo_unreserve(bo);
621 radeon_bo_unref(&bo);
622 return r;
623 }
624
625 /* stitch together an UVD create msg */
Alex Deucherc139b1e2013-06-07 10:04:54 -0400626 msg[0] = cpu_to_le32(0x00000de4);
627 msg[1] = cpu_to_le32(0x00000000);
628 msg[2] = cpu_to_le32(handle);
629 msg[3] = cpu_to_le32(0x00000000);
630 msg[4] = cpu_to_le32(0x00000000);
631 msg[5] = cpu_to_le32(0x00000000);
632 msg[6] = cpu_to_le32(0x00000000);
633 msg[7] = cpu_to_le32(0x00000780);
634 msg[8] = cpu_to_le32(0x00000440);
635 msg[9] = cpu_to_le32(0x00000000);
636 msg[10] = cpu_to_le32(0x01b37000);
Christian Königf2ba57b2013-04-08 12:41:29 +0200637 for (i = 11; i < 1024; ++i)
Alex Deucherc139b1e2013-06-07 10:04:54 -0400638 msg[i] = cpu_to_le32(0x0);
Christian Königf2ba57b2013-04-08 12:41:29 +0200639
640 radeon_bo_kunmap(bo);
641 radeon_bo_unreserve(bo);
642
643 return radeon_uvd_send_msg(rdev, ring, bo, fence);
644}
645
646int radeon_uvd_get_destroy_msg(struct radeon_device *rdev, int ring,
647 uint32_t handle, struct radeon_fence **fence)
648{
649 struct radeon_bo *bo;
650 uint32_t *msg;
651 int r, i;
652
653 r = radeon_bo_create(rdev, 1024, PAGE_SIZE, true,
654 RADEON_GEM_DOMAIN_VRAM, NULL, &bo);
655 if (r)
656 return r;
657
658 r = radeon_bo_reserve(bo, false);
659 if (r) {
660 radeon_bo_unref(&bo);
661 return r;
662 }
663
664 r = radeon_bo_kmap(bo, (void **)&msg);
665 if (r) {
666 radeon_bo_unreserve(bo);
667 radeon_bo_unref(&bo);
668 return r;
669 }
670
671 /* stitch together an UVD destroy msg */
Alex Deucherc139b1e2013-06-07 10:04:54 -0400672 msg[0] = cpu_to_le32(0x00000de4);
673 msg[1] = cpu_to_le32(0x00000002);
674 msg[2] = cpu_to_le32(handle);
675 msg[3] = cpu_to_le32(0x00000000);
Christian Königf2ba57b2013-04-08 12:41:29 +0200676 for (i = 4; i < 1024; ++i)
Alex Deucherc139b1e2013-06-07 10:04:54 -0400677 msg[i] = cpu_to_le32(0x0);
Christian Königf2ba57b2013-04-08 12:41:29 +0200678
679 radeon_bo_kunmap(bo);
680 radeon_bo_unreserve(bo);
681
682 return radeon_uvd_send_msg(rdev, ring, bo, fence);
683}
Christian König55b51c82013-04-18 15:25:59 +0200684
685static void radeon_uvd_idle_work_handler(struct work_struct *work)
686{
687 struct radeon_device *rdev =
688 container_of(work, struct radeon_device, uvd.idle_work.work);
689
690 if (radeon_fence_count_emitted(rdev, R600_RING_TYPE_UVD_INDEX) == 0)
691 radeon_set_uvd_clocks(rdev, 0, 0);
692 else
693 schedule_delayed_work(&rdev->uvd.idle_work,
694 msecs_to_jiffies(UVD_IDLE_TIMEOUT_MS));
695}
696
697void radeon_uvd_note_usage(struct radeon_device *rdev)
698{
699 bool set_clocks = !cancel_delayed_work_sync(&rdev->uvd.idle_work);
700 set_clocks &= schedule_delayed_work(&rdev->uvd.idle_work,
701 msecs_to_jiffies(UVD_IDLE_TIMEOUT_MS));
702 if (set_clocks)
703 radeon_set_uvd_clocks(rdev, 53300, 40000);
704}
Christian Königfacd1122013-04-29 11:55:02 +0200705
706static unsigned radeon_uvd_calc_upll_post_div(unsigned vco_freq,
707 unsigned target_freq,
708 unsigned pd_min,
709 unsigned pd_even)
710{
711 unsigned post_div = vco_freq / target_freq;
712
713 /* adjust to post divider minimum value */
714 if (post_div < pd_min)
715 post_div = pd_min;
716
717 /* we alway need a frequency less than or equal the target */
718 if ((vco_freq / post_div) > target_freq)
719 post_div += 1;
720
721 /* post dividers above a certain value must be even */
722 if (post_div > pd_even && post_div % 2)
723 post_div += 1;
724
725 return post_div;
726}
727
728/**
729 * radeon_uvd_calc_upll_dividers - calc UPLL clock dividers
730 *
731 * @rdev: radeon_device pointer
732 * @vclk: wanted VCLK
733 * @dclk: wanted DCLK
734 * @vco_min: minimum VCO frequency
735 * @vco_max: maximum VCO frequency
736 * @fb_factor: factor to multiply vco freq with
737 * @fb_mask: limit and bitmask for feedback divider
738 * @pd_min: post divider minimum
739 * @pd_max: post divider maximum
740 * @pd_even: post divider must be even above this value
741 * @optimal_fb_div: resulting feedback divider
742 * @optimal_vclk_div: resulting vclk post divider
743 * @optimal_dclk_div: resulting dclk post divider
744 *
745 * Calculate dividers for UVDs UPLL (R6xx-SI, except APUs).
746 * Returns zero on success -EINVAL on error.
747 */
748int radeon_uvd_calc_upll_dividers(struct radeon_device *rdev,
749 unsigned vclk, unsigned dclk,
750 unsigned vco_min, unsigned vco_max,
751 unsigned fb_factor, unsigned fb_mask,
752 unsigned pd_min, unsigned pd_max,
753 unsigned pd_even,
754 unsigned *optimal_fb_div,
755 unsigned *optimal_vclk_div,
756 unsigned *optimal_dclk_div)
757{
758 unsigned vco_freq, ref_freq = rdev->clock.spll.reference_freq;
759
760 /* start off with something large */
761 unsigned optimal_score = ~0;
762
763 /* loop through vco from low to high */
764 vco_min = max(max(vco_min, vclk), dclk);
765 for (vco_freq = vco_min; vco_freq <= vco_max; vco_freq += 100) {
766
767 uint64_t fb_div = (uint64_t)vco_freq * fb_factor;
768 unsigned vclk_div, dclk_div, score;
769
770 do_div(fb_div, ref_freq);
771
772 /* fb div out of range ? */
773 if (fb_div > fb_mask)
774 break; /* it can oly get worse */
775
776 fb_div &= fb_mask;
777
778 /* calc vclk divider with current vco freq */
779 vclk_div = radeon_uvd_calc_upll_post_div(vco_freq, vclk,
780 pd_min, pd_even);
781 if (vclk_div > pd_max)
782 break; /* vco is too big, it has to stop */
783
784 /* calc dclk divider with current vco freq */
785 dclk_div = radeon_uvd_calc_upll_post_div(vco_freq, dclk,
786 pd_min, pd_even);
787 if (vclk_div > pd_max)
788 break; /* vco is too big, it has to stop */
789
790 /* calc score with current vco freq */
791 score = vclk - (vco_freq / vclk_div) + dclk - (vco_freq / dclk_div);
792
793 /* determine if this vco setting is better than current optimal settings */
794 if (score < optimal_score) {
795 *optimal_fb_div = fb_div;
796 *optimal_vclk_div = vclk_div;
797 *optimal_dclk_div = dclk_div;
798 optimal_score = score;
799 if (optimal_score == 0)
800 break; /* it can't get better than this */
801 }
802 }
803
804 /* did we found a valid setup ? */
805 if (optimal_score == ~0)
806 return -EINVAL;
807
808 return 0;
809}
810
811int radeon_uvd_send_upll_ctlreq(struct radeon_device *rdev,
812 unsigned cg_upll_func_cntl)
813{
814 unsigned i;
815
816 /* make sure UPLL_CTLREQ is deasserted */
817 WREG32_P(cg_upll_func_cntl, 0, ~UPLL_CTLREQ_MASK);
818
819 mdelay(10);
820
821 /* assert UPLL_CTLREQ */
822 WREG32_P(cg_upll_func_cntl, UPLL_CTLREQ_MASK, ~UPLL_CTLREQ_MASK);
823
824 /* wait for CTLACK and CTLACK2 to get asserted */
825 for (i = 0; i < 100; ++i) {
826 uint32_t mask = UPLL_CTLACK_MASK | UPLL_CTLACK2_MASK;
827 if ((RREG32(cg_upll_func_cntl) & mask) == mask)
828 break;
829 mdelay(10);
830 }
831
832 /* deassert UPLL_CTLREQ */
833 WREG32_P(cg_upll_func_cntl, 0, ~UPLL_CTLREQ_MASK);
834
835 if (i == 100) {
836 DRM_ERROR("Timeout setting UVD clocks!\n");
837 return -ETIMEDOUT;
838 }
839
840 return 0;
841}