diff options
Diffstat (limited to 'drivers/gpu/drm/amd/amdgpu/dce_virtual.c')
-rw-r--r-- | drivers/gpu/drm/amd/amdgpu/dce_virtual.c | 432 |
1 files changed, 232 insertions, 200 deletions
diff --git a/drivers/gpu/drm/amd/amdgpu/dce_virtual.c b/drivers/gpu/drm/amd/amdgpu/dce_virtual.c index c2bd9f045532..cc85676a68d9 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_virtual.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_virtual.c | |||
@@ -27,6 +27,9 @@ | |||
27 | #include "atom.h" | 27 | #include "atom.h" |
28 | #include "amdgpu_pll.h" | 28 | #include "amdgpu_pll.h" |
29 | #include "amdgpu_connectors.h" | 29 | #include "amdgpu_connectors.h" |
30 | #ifdef CONFIG_DRM_AMDGPU_SI | ||
31 | #include "dce_v6_0.h" | ||
32 | #endif | ||
30 | #ifdef CONFIG_DRM_AMDGPU_CIK | 33 | #ifdef CONFIG_DRM_AMDGPU_CIK |
31 | #include "dce_v8_0.h" | 34 | #include "dce_v8_0.h" |
32 | #endif | 35 | #endif |
@@ -34,11 +37,13 @@ | |||
34 | #include "dce_v11_0.h" | 37 | #include "dce_v11_0.h" |
35 | #include "dce_virtual.h" | 38 | #include "dce_virtual.h" |
36 | 39 | ||
40 | #define DCE_VIRTUAL_VBLANK_PERIOD 16666666 | ||
41 | |||
42 | |||
37 | static void dce_virtual_set_display_funcs(struct amdgpu_device *adev); | 43 | static void dce_virtual_set_display_funcs(struct amdgpu_device *adev); |
38 | static void dce_virtual_set_irq_funcs(struct amdgpu_device *adev); | 44 | static void dce_virtual_set_irq_funcs(struct amdgpu_device *adev); |
39 | static int dce_virtual_pageflip_irq(struct amdgpu_device *adev, | 45 | static int dce_virtual_connector_encoder_init(struct amdgpu_device *adev, |
40 | struct amdgpu_irq_src *source, | 46 | int index); |
41 | struct amdgpu_iv_entry *entry); | ||
42 | 47 | ||
43 | /** | 48 | /** |
44 | * dce_virtual_vblank_wait - vblank wait asic callback. | 49 | * dce_virtual_vblank_wait - vblank wait asic callback. |
@@ -99,6 +104,14 @@ static void dce_virtual_stop_mc_access(struct amdgpu_device *adev, | |||
99 | struct amdgpu_mode_mc_save *save) | 104 | struct amdgpu_mode_mc_save *save) |
100 | { | 105 | { |
101 | switch (adev->asic_type) { | 106 | switch (adev->asic_type) { |
107 | #ifdef CONFIG_DRM_AMDGPU_SI | ||
108 | case CHIP_TAHITI: | ||
109 | case CHIP_PITCAIRN: | ||
110 | case CHIP_VERDE: | ||
111 | case CHIP_OLAND: | ||
112 | dce_v6_0_disable_dce(adev); | ||
113 | break; | ||
114 | #endif | ||
102 | #ifdef CONFIG_DRM_AMDGPU_CIK | 115 | #ifdef CONFIG_DRM_AMDGPU_CIK |
103 | case CHIP_BONAIRE: | 116 | case CHIP_BONAIRE: |
104 | case CHIP_HAWAII: | 117 | case CHIP_HAWAII: |
@@ -119,6 +132,9 @@ static void dce_virtual_stop_mc_access(struct amdgpu_device *adev, | |||
119 | dce_v11_0_disable_dce(adev); | 132 | dce_v11_0_disable_dce(adev); |
120 | break; | 133 | break; |
121 | case CHIP_TOPAZ: | 134 | case CHIP_TOPAZ: |
135 | #ifdef CONFIG_DRM_AMDGPU_SI | ||
136 | case CHIP_HAINAN: | ||
137 | #endif | ||
122 | /* no DCE */ | 138 | /* no DCE */ |
123 | return; | 139 | return; |
124 | default: | 140 | default: |
@@ -195,10 +211,9 @@ static void dce_virtual_crtc_dpms(struct drm_crtc *crtc, int mode) | |||
195 | switch (mode) { | 211 | switch (mode) { |
196 | case DRM_MODE_DPMS_ON: | 212 | case DRM_MODE_DPMS_ON: |
197 | amdgpu_crtc->enabled = true; | 213 | amdgpu_crtc->enabled = true; |
198 | /* Make sure VBLANK and PFLIP interrupts are still enabled */ | 214 | /* Make sure VBLANK interrupts are still enabled */ |
199 | type = amdgpu_crtc_idx_to_irq_type(adev, amdgpu_crtc->crtc_id); | 215 | type = amdgpu_crtc_idx_to_irq_type(adev, amdgpu_crtc->crtc_id); |
200 | amdgpu_irq_update(adev, &adev->crtc_irq, type); | 216 | amdgpu_irq_update(adev, &adev->crtc_irq, type); |
201 | amdgpu_irq_update(adev, &adev->pageflip_irq, type); | ||
202 | drm_vblank_on(dev, amdgpu_crtc->crtc_id); | 217 | drm_vblank_on(dev, amdgpu_crtc->crtc_id); |
203 | break; | 218 | break; |
204 | case DRM_MODE_DPMS_STANDBY: | 219 | case DRM_MODE_DPMS_STANDBY: |
@@ -264,24 +279,6 @@ static bool dce_virtual_crtc_mode_fixup(struct drm_crtc *crtc, | |||
264 | const struct drm_display_mode *mode, | 279 | const struct drm_display_mode *mode, |
265 | struct drm_display_mode *adjusted_mode) | 280 | struct drm_display_mode *adjusted_mode) |
266 | { | 281 | { |
267 | struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); | ||
268 | struct drm_device *dev = crtc->dev; | ||
269 | struct drm_encoder *encoder; | ||
270 | |||
271 | /* assign the encoder to the amdgpu crtc to avoid repeated lookups later */ | ||
272 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { | ||
273 | if (encoder->crtc == crtc) { | ||
274 | amdgpu_crtc->encoder = encoder; | ||
275 | amdgpu_crtc->connector = amdgpu_get_connector_for_encoder(encoder); | ||
276 | break; | ||
277 | } | ||
278 | } | ||
279 | if ((amdgpu_crtc->encoder == NULL) || (amdgpu_crtc->connector == NULL)) { | ||
280 | amdgpu_crtc->encoder = NULL; | ||
281 | amdgpu_crtc->connector = NULL; | ||
282 | return false; | ||
283 | } | ||
284 | |||
285 | return true; | 282 | return true; |
286 | } | 283 | } |
287 | 284 | ||
@@ -341,6 +338,7 @@ static int dce_virtual_crtc_init(struct amdgpu_device *adev, int index) | |||
341 | amdgpu_crtc->pll_id = ATOM_PPLL_INVALID; | 338 | amdgpu_crtc->pll_id = ATOM_PPLL_INVALID; |
342 | amdgpu_crtc->encoder = NULL; | 339 | amdgpu_crtc->encoder = NULL; |
343 | amdgpu_crtc->connector = NULL; | 340 | amdgpu_crtc->connector = NULL; |
341 | amdgpu_crtc->vsync_timer_enabled = AMDGPU_IRQ_STATE_DISABLE; | ||
344 | drm_crtc_helper_add(&amdgpu_crtc->base, &dce_virtual_crtc_helper_funcs); | 342 | drm_crtc_helper_add(&amdgpu_crtc->base, &dce_virtual_crtc_helper_funcs); |
345 | 343 | ||
346 | return 0; | 344 | return 0; |
@@ -350,48 +348,128 @@ static int dce_virtual_early_init(void *handle) | |||
350 | { | 348 | { |
351 | struct amdgpu_device *adev = (struct amdgpu_device *)handle; | 349 | struct amdgpu_device *adev = (struct amdgpu_device *)handle; |
352 | 350 | ||
353 | adev->mode_info.vsync_timer_enabled = AMDGPU_IRQ_STATE_DISABLE; | ||
354 | dce_virtual_set_display_funcs(adev); | 351 | dce_virtual_set_display_funcs(adev); |
355 | dce_virtual_set_irq_funcs(adev); | 352 | dce_virtual_set_irq_funcs(adev); |
356 | 353 | ||
357 | adev->mode_info.num_crtc = 1; | ||
358 | adev->mode_info.num_hpd = 1; | 354 | adev->mode_info.num_hpd = 1; |
359 | adev->mode_info.num_dig = 1; | 355 | adev->mode_info.num_dig = 1; |
360 | return 0; | 356 | return 0; |
361 | } | 357 | } |
362 | 358 | ||
363 | static bool dce_virtual_get_connector_info(struct amdgpu_device *adev) | 359 | static struct drm_encoder * |
360 | dce_virtual_encoder(struct drm_connector *connector) | ||
364 | { | 361 | { |
365 | struct amdgpu_i2c_bus_rec ddc_bus; | 362 | int enc_id = connector->encoder_ids[0]; |
366 | struct amdgpu_router router; | 363 | struct drm_encoder *encoder; |
367 | struct amdgpu_hpd hpd; | 364 | int i; |
368 | 365 | ||
369 | /* look up gpio for ddc, hpd */ | 366 | for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { |
370 | ddc_bus.valid = false; | 367 | if (connector->encoder_ids[i] == 0) |
371 | hpd.hpd = AMDGPU_HPD_NONE; | 368 | break; |
372 | /* needed for aux chan transactions */ | ||
373 | ddc_bus.hpd = hpd.hpd; | ||
374 | 369 | ||
375 | memset(&router, 0, sizeof(router)); | 370 | encoder = drm_encoder_find(connector->dev, connector->encoder_ids[i]); |
376 | router.ddc_valid = false; | 371 | if (!encoder) |
377 | router.cd_valid = false; | 372 | continue; |
378 | amdgpu_display_add_connector(adev, | ||
379 | 0, | ||
380 | ATOM_DEVICE_CRT1_SUPPORT, | ||
381 | DRM_MODE_CONNECTOR_VIRTUAL, &ddc_bus, | ||
382 | CONNECTOR_OBJECT_ID_VIRTUAL, | ||
383 | &hpd, | ||
384 | &router); | ||
385 | 373 | ||
386 | amdgpu_display_add_encoder(adev, ENCODER_VIRTUAL_ENUM_VIRTUAL, | 374 | if (encoder->encoder_type == DRM_MODE_ENCODER_VIRTUAL) |
387 | ATOM_DEVICE_CRT1_SUPPORT, | 375 | return encoder; |
388 | 0); | 376 | } |
389 | 377 | ||
390 | amdgpu_link_encoder_connector(adev->ddev); | 378 | /* pick the first one */ |
379 | if (enc_id) | ||
380 | return drm_encoder_find(connector->dev, enc_id); | ||
381 | return NULL; | ||
382 | } | ||
383 | |||
384 | static int dce_virtual_get_modes(struct drm_connector *connector) | ||
385 | { | ||
386 | struct drm_device *dev = connector->dev; | ||
387 | struct drm_display_mode *mode = NULL; | ||
388 | unsigned i; | ||
389 | static const struct mode_size { | ||
390 | int w; | ||
391 | int h; | ||
392 | } common_modes[17] = { | ||
393 | { 640, 480}, | ||
394 | { 720, 480}, | ||
395 | { 800, 600}, | ||
396 | { 848, 480}, | ||
397 | {1024, 768}, | ||
398 | {1152, 768}, | ||
399 | {1280, 720}, | ||
400 | {1280, 800}, | ||
401 | {1280, 854}, | ||
402 | {1280, 960}, | ||
403 | {1280, 1024}, | ||
404 | {1440, 900}, | ||
405 | {1400, 1050}, | ||
406 | {1680, 1050}, | ||
407 | {1600, 1200}, | ||
408 | {1920, 1080}, | ||
409 | {1920, 1200} | ||
410 | }; | ||
411 | |||
412 | for (i = 0; i < 17; i++) { | ||
413 | mode = drm_cvt_mode(dev, common_modes[i].w, common_modes[i].h, 60, false, false, false); | ||
414 | drm_mode_probed_add(connector, mode); | ||
415 | } | ||
391 | 416 | ||
392 | return true; | 417 | return 0; |
418 | } | ||
419 | |||
420 | static int dce_virtual_mode_valid(struct drm_connector *connector, | ||
421 | struct drm_display_mode *mode) | ||
422 | { | ||
423 | return MODE_OK; | ||
424 | } | ||
425 | |||
426 | static int | ||
427 | dce_virtual_dpms(struct drm_connector *connector, int mode) | ||
428 | { | ||
429 | return 0; | ||
393 | } | 430 | } |
394 | 431 | ||
432 | static enum drm_connector_status | ||
433 | dce_virtual_detect(struct drm_connector *connector, bool force) | ||
434 | { | ||
435 | return connector_status_connected; | ||
436 | } | ||
437 | |||
438 | static int | ||
439 | dce_virtual_set_property(struct drm_connector *connector, | ||
440 | struct drm_property *property, | ||
441 | uint64_t val) | ||
442 | { | ||
443 | return 0; | ||
444 | } | ||
445 | |||
446 | static void dce_virtual_destroy(struct drm_connector *connector) | ||
447 | { | ||
448 | drm_connector_unregister(connector); | ||
449 | drm_connector_cleanup(connector); | ||
450 | kfree(connector); | ||
451 | } | ||
452 | |||
453 | static void dce_virtual_force(struct drm_connector *connector) | ||
454 | { | ||
455 | return; | ||
456 | } | ||
457 | |||
458 | static const struct drm_connector_helper_funcs dce_virtual_connector_helper_funcs = { | ||
459 | .get_modes = dce_virtual_get_modes, | ||
460 | .mode_valid = dce_virtual_mode_valid, | ||
461 | .best_encoder = dce_virtual_encoder, | ||
462 | }; | ||
463 | |||
464 | static const struct drm_connector_funcs dce_virtual_connector_funcs = { | ||
465 | .dpms = dce_virtual_dpms, | ||
466 | .detect = dce_virtual_detect, | ||
467 | .fill_modes = drm_helper_probe_single_connector_modes, | ||
468 | .set_property = dce_virtual_set_property, | ||
469 | .destroy = dce_virtual_destroy, | ||
470 | .force = dce_virtual_force, | ||
471 | }; | ||
472 | |||
395 | static int dce_virtual_sw_init(void *handle) | 473 | static int dce_virtual_sw_init(void *handle) |
396 | { | 474 | { |
397 | int r, i; | 475 | int r, i; |
@@ -420,16 +498,16 @@ static int dce_virtual_sw_init(void *handle) | |||
420 | adev->ddev->mode_config.max_width = 16384; | 498 | adev->ddev->mode_config.max_width = 16384; |
421 | adev->ddev->mode_config.max_height = 16384; | 499 | adev->ddev->mode_config.max_height = 16384; |
422 | 500 | ||
423 | /* allocate crtcs */ | 501 | /* allocate crtcs, encoders, connectors */ |
424 | for (i = 0; i < adev->mode_info.num_crtc; i++) { | 502 | for (i = 0; i < adev->mode_info.num_crtc; i++) { |
425 | r = dce_virtual_crtc_init(adev, i); | 503 | r = dce_virtual_crtc_init(adev, i); |
426 | if (r) | 504 | if (r) |
427 | return r; | 505 | return r; |
506 | r = dce_virtual_connector_encoder_init(adev, i); | ||
507 | if (r) | ||
508 | return r; | ||
428 | } | 509 | } |
429 | 510 | ||
430 | dce_virtual_get_connector_info(adev); | ||
431 | amdgpu_print_display_setup(adev->ddev); | ||
432 | |||
433 | drm_kms_helper_poll_init(adev->ddev); | 511 | drm_kms_helper_poll_init(adev->ddev); |
434 | 512 | ||
435 | adev->mode_info.mode_config_initialized = true; | 513 | adev->mode_info.mode_config_initialized = true; |
@@ -496,7 +574,7 @@ static int dce_virtual_set_powergating_state(void *handle, | |||
496 | return 0; | 574 | return 0; |
497 | } | 575 | } |
498 | 576 | ||
499 | const struct amd_ip_funcs dce_virtual_ip_funcs = { | 577 | static const struct amd_ip_funcs dce_virtual_ip_funcs = { |
500 | .name = "dce_virtual", | 578 | .name = "dce_virtual", |
501 | .early_init = dce_virtual_early_init, | 579 | .early_init = dce_virtual_early_init, |
502 | .late_init = NULL, | 580 | .late_init = NULL, |
@@ -526,8 +604,8 @@ static void dce_virtual_encoder_commit(struct drm_encoder *encoder) | |||
526 | 604 | ||
527 | static void | 605 | static void |
528 | dce_virtual_encoder_mode_set(struct drm_encoder *encoder, | 606 | dce_virtual_encoder_mode_set(struct drm_encoder *encoder, |
529 | struct drm_display_mode *mode, | 607 | struct drm_display_mode *mode, |
530 | struct drm_display_mode *adjusted_mode) | 608 | struct drm_display_mode *adjusted_mode) |
531 | { | 609 | { |
532 | return; | 610 | return; |
533 | } | 611 | } |
@@ -547,10 +625,6 @@ static bool dce_virtual_encoder_mode_fixup(struct drm_encoder *encoder, | |||
547 | const struct drm_display_mode *mode, | 625 | const struct drm_display_mode *mode, |
548 | struct drm_display_mode *adjusted_mode) | 626 | struct drm_display_mode *adjusted_mode) |
549 | { | 627 | { |
550 | |||
551 | /* set the active encoder to connector routing */ | ||
552 | amdgpu_encoder_set_active_device(encoder); | ||
553 | |||
554 | return true; | 628 | return true; |
555 | } | 629 | } |
556 | 630 | ||
@@ -576,45 +650,40 @@ static const struct drm_encoder_funcs dce_virtual_encoder_funcs = { | |||
576 | .destroy = dce_virtual_encoder_destroy, | 650 | .destroy = dce_virtual_encoder_destroy, |
577 | }; | 651 | }; |
578 | 652 | ||
579 | static void dce_virtual_encoder_add(struct amdgpu_device *adev, | 653 | static int dce_virtual_connector_encoder_init(struct amdgpu_device *adev, |
580 | uint32_t encoder_enum, | 654 | int index) |
581 | uint32_t supported_device, | ||
582 | u16 caps) | ||
583 | { | 655 | { |
584 | struct drm_device *dev = adev->ddev; | ||
585 | struct drm_encoder *encoder; | 656 | struct drm_encoder *encoder; |
586 | struct amdgpu_encoder *amdgpu_encoder; | 657 | struct drm_connector *connector; |
587 | 658 | ||
588 | /* see if we already added it */ | 659 | /* add a new encoder */ |
589 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { | 660 | encoder = kzalloc(sizeof(struct drm_encoder), GFP_KERNEL); |
590 | amdgpu_encoder = to_amdgpu_encoder(encoder); | 661 | if (!encoder) |
591 | if (amdgpu_encoder->encoder_enum == encoder_enum) { | 662 | return -ENOMEM; |
592 | amdgpu_encoder->devices |= supported_device; | 663 | encoder->possible_crtcs = 1 << index; |
593 | return; | 664 | drm_encoder_init(adev->ddev, encoder, &dce_virtual_encoder_funcs, |
594 | } | 665 | DRM_MODE_ENCODER_VIRTUAL, NULL); |
666 | drm_encoder_helper_add(encoder, &dce_virtual_encoder_helper_funcs); | ||
595 | 667 | ||
668 | connector = kzalloc(sizeof(struct drm_connector), GFP_KERNEL); | ||
669 | if (!connector) { | ||
670 | kfree(encoder); | ||
671 | return -ENOMEM; | ||
596 | } | 672 | } |
597 | 673 | ||
598 | /* add a new one */ | 674 | /* add a new connector */ |
599 | amdgpu_encoder = kzalloc(sizeof(struct amdgpu_encoder), GFP_KERNEL); | 675 | drm_connector_init(adev->ddev, connector, &dce_virtual_connector_funcs, |
600 | if (!amdgpu_encoder) | 676 | DRM_MODE_CONNECTOR_VIRTUAL); |
601 | return; | 677 | drm_connector_helper_add(connector, &dce_virtual_connector_helper_funcs); |
678 | connector->display_info.subpixel_order = SubPixelHorizontalRGB; | ||
679 | connector->interlace_allowed = false; | ||
680 | connector->doublescan_allowed = false; | ||
681 | drm_connector_register(connector); | ||
602 | 682 | ||
603 | encoder = &amdgpu_encoder->base; | 683 | /* link them */ |
604 | encoder->possible_crtcs = 0x1; | 684 | drm_mode_connector_attach_encoder(connector, encoder); |
605 | amdgpu_encoder->enc_priv = NULL; | 685 | |
606 | amdgpu_encoder->encoder_enum = encoder_enum; | 686 | return 0; |
607 | amdgpu_encoder->encoder_id = (encoder_enum & OBJECT_ID_MASK) >> OBJECT_ID_SHIFT; | ||
608 | amdgpu_encoder->devices = supported_device; | ||
609 | amdgpu_encoder->rmx_type = RMX_OFF; | ||
610 | amdgpu_encoder->underscan_type = UNDERSCAN_OFF; | ||
611 | amdgpu_encoder->is_ext_encoder = false; | ||
612 | amdgpu_encoder->caps = caps; | ||
613 | |||
614 | drm_encoder_init(dev, encoder, &dce_virtual_encoder_funcs, | ||
615 | DRM_MODE_ENCODER_VIRTUAL, NULL); | ||
616 | drm_encoder_helper_add(encoder, &dce_virtual_encoder_helper_funcs); | ||
617 | DRM_INFO("[FM]encoder: %d is VIRTUAL\n", amdgpu_encoder->encoder_id); | ||
618 | } | 687 | } |
619 | 688 | ||
620 | static const struct amdgpu_display_funcs dce_virtual_display_funcs = { | 689 | static const struct amdgpu_display_funcs dce_virtual_display_funcs = { |
@@ -630,8 +699,8 @@ static const struct amdgpu_display_funcs dce_virtual_display_funcs = { | |||
630 | .hpd_get_gpio_reg = &dce_virtual_hpd_get_gpio_reg, | 699 | .hpd_get_gpio_reg = &dce_virtual_hpd_get_gpio_reg, |
631 | .page_flip = &dce_virtual_page_flip, | 700 | .page_flip = &dce_virtual_page_flip, |
632 | .page_flip_get_scanoutpos = &dce_virtual_crtc_get_scanoutpos, | 701 | .page_flip_get_scanoutpos = &dce_virtual_crtc_get_scanoutpos, |
633 | .add_encoder = &dce_virtual_encoder_add, | 702 | .add_encoder = NULL, |
634 | .add_connector = &amdgpu_connector_add, | 703 | .add_connector = NULL, |
635 | .stop_mc_access = &dce_virtual_stop_mc_access, | 704 | .stop_mc_access = &dce_virtual_stop_mc_access, |
636 | .resume_mc_access = &dce_virtual_resume_mc_access, | 705 | .resume_mc_access = &dce_virtual_resume_mc_access, |
637 | }; | 706 | }; |
@@ -642,107 +711,13 @@ static void dce_virtual_set_display_funcs(struct amdgpu_device *adev) | |||
642 | adev->mode_info.funcs = &dce_virtual_display_funcs; | 711 | adev->mode_info.funcs = &dce_virtual_display_funcs; |
643 | } | 712 | } |
644 | 713 | ||
645 | static enum hrtimer_restart dce_virtual_vblank_timer_handle(struct hrtimer *vblank_timer) | 714 | static int dce_virtual_pageflip(struct amdgpu_device *adev, |
646 | { | 715 | unsigned crtc_id) |
647 | struct amdgpu_mode_info *mode_info = container_of(vblank_timer, struct amdgpu_mode_info ,vblank_timer); | ||
648 | struct amdgpu_device *adev = container_of(mode_info, struct amdgpu_device ,mode_info); | ||
649 | unsigned crtc = 0; | ||
650 | drm_handle_vblank(adev->ddev, crtc); | ||
651 | dce_virtual_pageflip_irq(adev, NULL, NULL); | ||
652 | hrtimer_start(vblank_timer, ktime_set(0, DCE_VIRTUAL_VBLANK_PERIOD), HRTIMER_MODE_REL); | ||
653 | return HRTIMER_NORESTART; | ||
654 | } | ||
655 | |||
656 | static void dce_virtual_set_crtc_vblank_interrupt_state(struct amdgpu_device *adev, | ||
657 | int crtc, | ||
658 | enum amdgpu_interrupt_state state) | ||
659 | { | ||
660 | if (crtc >= adev->mode_info.num_crtc) { | ||
661 | DRM_DEBUG("invalid crtc %d\n", crtc); | ||
662 | return; | ||
663 | } | ||
664 | |||
665 | if (state && !adev->mode_info.vsync_timer_enabled) { | ||
666 | DRM_DEBUG("Enable software vsync timer\n"); | ||
667 | hrtimer_init(&adev->mode_info.vblank_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); | ||
668 | hrtimer_set_expires(&adev->mode_info.vblank_timer, ktime_set(0, DCE_VIRTUAL_VBLANK_PERIOD)); | ||
669 | adev->mode_info.vblank_timer.function = dce_virtual_vblank_timer_handle; | ||
670 | hrtimer_start(&adev->mode_info.vblank_timer, ktime_set(0, DCE_VIRTUAL_VBLANK_PERIOD), HRTIMER_MODE_REL); | ||
671 | } else if (!state && adev->mode_info.vsync_timer_enabled) { | ||
672 | DRM_DEBUG("Disable software vsync timer\n"); | ||
673 | hrtimer_cancel(&adev->mode_info.vblank_timer); | ||
674 | } | ||
675 | |||
676 | adev->mode_info.vsync_timer_enabled = state; | ||
677 | DRM_DEBUG("[FM]set crtc %d vblank interrupt state %d\n", crtc, state); | ||
678 | } | ||
679 | |||
680 | |||
681 | static int dce_virtual_set_crtc_irq_state(struct amdgpu_device *adev, | ||
682 | struct amdgpu_irq_src *source, | ||
683 | unsigned type, | ||
684 | enum amdgpu_interrupt_state state) | ||
685 | { | ||
686 | switch (type) { | ||
687 | case AMDGPU_CRTC_IRQ_VBLANK1: | ||
688 | dce_virtual_set_crtc_vblank_interrupt_state(adev, 0, state); | ||
689 | break; | ||
690 | default: | ||
691 | break; | ||
692 | } | ||
693 | return 0; | ||
694 | } | ||
695 | |||
696 | static void dce_virtual_crtc_vblank_int_ack(struct amdgpu_device *adev, | ||
697 | int crtc) | ||
698 | { | ||
699 | if (crtc >= adev->mode_info.num_crtc) { | ||
700 | DRM_DEBUG("invalid crtc %d\n", crtc); | ||
701 | return; | ||
702 | } | ||
703 | } | ||
704 | |||
705 | static int dce_virtual_crtc_irq(struct amdgpu_device *adev, | ||
706 | struct amdgpu_irq_src *source, | ||
707 | struct amdgpu_iv_entry *entry) | ||
708 | { | ||
709 | unsigned crtc = 0; | ||
710 | unsigned irq_type = AMDGPU_CRTC_IRQ_VBLANK1; | ||
711 | |||
712 | dce_virtual_crtc_vblank_int_ack(adev, crtc); | ||
713 | |||
714 | if (amdgpu_irq_enabled(adev, source, irq_type)) { | ||
715 | drm_handle_vblank(adev->ddev, crtc); | ||
716 | } | ||
717 | dce_virtual_pageflip_irq(adev, NULL, NULL); | ||
718 | DRM_DEBUG("IH: D%d vblank\n", crtc + 1); | ||
719 | return 0; | ||
720 | } | ||
721 | |||
722 | static int dce_virtual_set_pageflip_irq_state(struct amdgpu_device *adev, | ||
723 | struct amdgpu_irq_src *src, | ||
724 | unsigned type, | ||
725 | enum amdgpu_interrupt_state state) | ||
726 | { | ||
727 | if (type >= adev->mode_info.num_crtc) { | ||
728 | DRM_ERROR("invalid pageflip crtc %d\n", type); | ||
729 | return -EINVAL; | ||
730 | } | ||
731 | DRM_DEBUG("[FM]set pageflip irq type %d state %d\n", type, state); | ||
732 | |||
733 | return 0; | ||
734 | } | ||
735 | |||
736 | static int dce_virtual_pageflip_irq(struct amdgpu_device *adev, | ||
737 | struct amdgpu_irq_src *source, | ||
738 | struct amdgpu_iv_entry *entry) | ||
739 | { | 716 | { |
740 | unsigned long flags; | 717 | unsigned long flags; |
741 | unsigned crtc_id = 0; | ||
742 | struct amdgpu_crtc *amdgpu_crtc; | 718 | struct amdgpu_crtc *amdgpu_crtc; |
743 | struct amdgpu_flip_work *works; | 719 | struct amdgpu_flip_work *works; |
744 | 720 | ||
745 | crtc_id = 0; | ||
746 | amdgpu_crtc = adev->mode_info.crtcs[crtc_id]; | 721 | amdgpu_crtc = adev->mode_info.crtcs[crtc_id]; |
747 | 722 | ||
748 | if (crtc_id >= adev->mode_info.num_crtc) { | 723 | if (crtc_id >= adev->mode_info.num_crtc) { |
@@ -781,22 +756,79 @@ static int dce_virtual_pageflip_irq(struct amdgpu_device *adev, | |||
781 | return 0; | 756 | return 0; |
782 | } | 757 | } |
783 | 758 | ||
759 | static enum hrtimer_restart dce_virtual_vblank_timer_handle(struct hrtimer *vblank_timer) | ||
760 | { | ||
761 | struct amdgpu_crtc *amdgpu_crtc = container_of(vblank_timer, | ||
762 | struct amdgpu_crtc, vblank_timer); | ||
763 | struct drm_device *ddev = amdgpu_crtc->base.dev; | ||
764 | struct amdgpu_device *adev = ddev->dev_private; | ||
765 | |||
766 | drm_handle_vblank(ddev, amdgpu_crtc->crtc_id); | ||
767 | dce_virtual_pageflip(adev, amdgpu_crtc->crtc_id); | ||
768 | hrtimer_start(vblank_timer, ktime_set(0, DCE_VIRTUAL_VBLANK_PERIOD), | ||
769 | HRTIMER_MODE_REL); | ||
770 | |||
771 | return HRTIMER_NORESTART; | ||
772 | } | ||
773 | |||
774 | static void dce_virtual_set_crtc_vblank_interrupt_state(struct amdgpu_device *adev, | ||
775 | int crtc, | ||
776 | enum amdgpu_interrupt_state state) | ||
777 | { | ||
778 | if (crtc >= adev->mode_info.num_crtc) { | ||
779 | DRM_DEBUG("invalid crtc %d\n", crtc); | ||
780 | return; | ||
781 | } | ||
782 | |||
783 | if (state && !adev->mode_info.crtcs[crtc]->vsync_timer_enabled) { | ||
784 | DRM_DEBUG("Enable software vsync timer\n"); | ||
785 | hrtimer_init(&adev->mode_info.crtcs[crtc]->vblank_timer, | ||
786 | CLOCK_MONOTONIC, HRTIMER_MODE_REL); | ||
787 | hrtimer_set_expires(&adev->mode_info.crtcs[crtc]->vblank_timer, | ||
788 | ktime_set(0, DCE_VIRTUAL_VBLANK_PERIOD)); | ||
789 | adev->mode_info.crtcs[crtc]->vblank_timer.function = | ||
790 | dce_virtual_vblank_timer_handle; | ||
791 | hrtimer_start(&adev->mode_info.crtcs[crtc]->vblank_timer, | ||
792 | ktime_set(0, DCE_VIRTUAL_VBLANK_PERIOD), HRTIMER_MODE_REL); | ||
793 | } else if (!state && adev->mode_info.crtcs[crtc]->vsync_timer_enabled) { | ||
794 | DRM_DEBUG("Disable software vsync timer\n"); | ||
795 | hrtimer_cancel(&adev->mode_info.crtcs[crtc]->vblank_timer); | ||
796 | } | ||
797 | |||
798 | adev->mode_info.crtcs[crtc]->vsync_timer_enabled = state; | ||
799 | DRM_DEBUG("[FM]set crtc %d vblank interrupt state %d\n", crtc, state); | ||
800 | } | ||
801 | |||
802 | |||
803 | static int dce_virtual_set_crtc_irq_state(struct amdgpu_device *adev, | ||
804 | struct amdgpu_irq_src *source, | ||
805 | unsigned type, | ||
806 | enum amdgpu_interrupt_state state) | ||
807 | { | ||
808 | if (type > AMDGPU_CRTC_IRQ_VBLANK6) | ||
809 | return -EINVAL; | ||
810 | |||
811 | dce_virtual_set_crtc_vblank_interrupt_state(adev, type, state); | ||
812 | |||
813 | return 0; | ||
814 | } | ||
815 | |||
784 | static const struct amdgpu_irq_src_funcs dce_virtual_crtc_irq_funcs = { | 816 | static const struct amdgpu_irq_src_funcs dce_virtual_crtc_irq_funcs = { |
785 | .set = dce_virtual_set_crtc_irq_state, | 817 | .set = dce_virtual_set_crtc_irq_state, |
786 | .process = dce_virtual_crtc_irq, | 818 | .process = NULL, |
787 | }; | ||
788 | |||
789 | static const struct amdgpu_irq_src_funcs dce_virtual_pageflip_irq_funcs = { | ||
790 | .set = dce_virtual_set_pageflip_irq_state, | ||
791 | .process = dce_virtual_pageflip_irq, | ||
792 | }; | 819 | }; |
793 | 820 | ||
794 | static void dce_virtual_set_irq_funcs(struct amdgpu_device *adev) | 821 | static void dce_virtual_set_irq_funcs(struct amdgpu_device *adev) |
795 | { | 822 | { |
796 | adev->crtc_irq.num_types = AMDGPU_CRTC_IRQ_LAST; | 823 | adev->crtc_irq.num_types = AMDGPU_CRTC_IRQ_LAST; |
797 | adev->crtc_irq.funcs = &dce_virtual_crtc_irq_funcs; | 824 | adev->crtc_irq.funcs = &dce_virtual_crtc_irq_funcs; |
798 | |||
799 | adev->pageflip_irq.num_types = AMDGPU_PAGEFLIP_IRQ_LAST; | ||
800 | adev->pageflip_irq.funcs = &dce_virtual_pageflip_irq_funcs; | ||
801 | } | 825 | } |
802 | 826 | ||
827 | const struct amdgpu_ip_block_version dce_virtual_ip_block = | ||
828 | { | ||
829 | .type = AMD_IP_BLOCK_TYPE_DCE, | ||
830 | .major = 1, | ||
831 | .minor = 0, | ||
832 | .rev = 0, | ||
833 | .funcs = &dce_virtual_ip_funcs, | ||
834 | }; | ||