| .. | .. |
|---|
| 20 | 20 | * OTHER DEALINGS IN THE SOFTWARE. |
|---|
| 21 | 21 | * |
|---|
| 22 | 22 | */ |
|---|
| 23 | | -#include <drm/drmP.h> |
|---|
| 23 | + |
|---|
| 24 | +#include <drm/drm_vblank.h> |
|---|
| 25 | + |
|---|
| 24 | 26 | #include "amdgpu.h" |
|---|
| 25 | 27 | #include "amdgpu_pm.h" |
|---|
| 26 | 28 | #include "amdgpu_i2c.h" |
|---|
| .. | .. |
|---|
| 45 | 47 | static void dce_virtual_set_irq_funcs(struct amdgpu_device *adev); |
|---|
| 46 | 48 | static int dce_virtual_connector_encoder_init(struct amdgpu_device *adev, |
|---|
| 47 | 49 | int index); |
|---|
| 50 | +static int dce_virtual_pageflip(struct amdgpu_device *adev, |
|---|
| 51 | + unsigned crtc_id); |
|---|
| 52 | +static enum hrtimer_restart dce_virtual_vblank_timer_handle(struct hrtimer *vblank_timer); |
|---|
| 48 | 53 | static void dce_virtual_set_crtc_vblank_interrupt_state(struct amdgpu_device *adev, |
|---|
| 49 | 54 | int crtc, |
|---|
| 50 | 55 | enum amdgpu_interrupt_state state); |
|---|
| .. | .. |
|---|
| 121 | 126 | .set_config = amdgpu_display_crtc_set_config, |
|---|
| 122 | 127 | .destroy = dce_virtual_crtc_destroy, |
|---|
| 123 | 128 | .page_flip_target = amdgpu_display_crtc_page_flip_target, |
|---|
| 129 | + .get_vblank_counter = amdgpu_get_vblank_counter_kms, |
|---|
| 130 | + .enable_vblank = amdgpu_enable_vblank_kms, |
|---|
| 131 | + .disable_vblank = amdgpu_disable_vblank_kms, |
|---|
| 132 | + .get_vblank_timestamp = drm_crtc_vblank_helper_get_vblank_timestamp, |
|---|
| 124 | 133 | }; |
|---|
| 125 | 134 | |
|---|
| 126 | 135 | static void dce_virtual_crtc_dpms(struct drm_crtc *crtc, int mode) |
|---|
| 127 | 136 | { |
|---|
| 128 | 137 | struct drm_device *dev = crtc->dev; |
|---|
| 129 | | - struct amdgpu_device *adev = dev->dev_private; |
|---|
| 138 | + struct amdgpu_device *adev = drm_to_adev(dev); |
|---|
| 130 | 139 | struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); |
|---|
| 131 | 140 | unsigned type; |
|---|
| 132 | 141 | |
|---|
| .. | .. |
|---|
| 165 | 174 | static void dce_virtual_crtc_disable(struct drm_crtc *crtc) |
|---|
| 166 | 175 | { |
|---|
| 167 | 176 | struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); |
|---|
| 177 | + struct drm_device *dev = crtc->dev; |
|---|
| 168 | 178 | |
|---|
| 169 | | - dce_virtual_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); |
|---|
| 170 | | - if (crtc->primary->fb) { |
|---|
| 171 | | - int r; |
|---|
| 172 | | - struct amdgpu_bo *abo; |
|---|
| 179 | + if (dev->num_crtcs) |
|---|
| 180 | + drm_crtc_vblank_off(crtc); |
|---|
| 173 | 181 | |
|---|
| 174 | | - abo = gem_to_amdgpu_bo(crtc->primary->fb->obj[0]); |
|---|
| 175 | | - r = amdgpu_bo_reserve(abo, true); |
|---|
| 176 | | - if (unlikely(r)) |
|---|
| 177 | | - DRM_ERROR("failed to reserve abo before unpin\n"); |
|---|
| 178 | | - else { |
|---|
| 179 | | - amdgpu_bo_unpin(abo); |
|---|
| 180 | | - amdgpu_bo_unreserve(abo); |
|---|
| 181 | | - } |
|---|
| 182 | | - } |
|---|
| 183 | | - |
|---|
| 182 | + amdgpu_crtc->enabled = false; |
|---|
| 184 | 183 | amdgpu_crtc->pll_id = ATOM_PPLL_INVALID; |
|---|
| 185 | 184 | amdgpu_crtc->encoder = NULL; |
|---|
| 186 | 185 | amdgpu_crtc->connector = NULL; |
|---|
| .. | .. |
|---|
| 229 | 228 | .prepare = dce_virtual_crtc_prepare, |
|---|
| 230 | 229 | .commit = dce_virtual_crtc_commit, |
|---|
| 231 | 230 | .disable = dce_virtual_crtc_disable, |
|---|
| 231 | + .get_scanout_position = amdgpu_crtc_get_scanout_position, |
|---|
| 232 | 232 | }; |
|---|
| 233 | 233 | |
|---|
| 234 | 234 | static int dce_virtual_crtc_init(struct amdgpu_device *adev, int index) |
|---|
| .. | .. |
|---|
| 240 | 240 | if (amdgpu_crtc == NULL) |
|---|
| 241 | 241 | return -ENOMEM; |
|---|
| 242 | 242 | |
|---|
| 243 | | - drm_crtc_init(adev->ddev, &amdgpu_crtc->base, &dce_virtual_crtc_funcs); |
|---|
| 243 | + drm_crtc_init(adev_to_drm(adev), &amdgpu_crtc->base, &dce_virtual_crtc_funcs); |
|---|
| 244 | 244 | |
|---|
| 245 | 245 | drm_mode_crtc_set_gamma_size(&amdgpu_crtc->base, 256); |
|---|
| 246 | 246 | amdgpu_crtc->crtc_id = index; |
|---|
| .. | .. |
|---|
| 252 | 252 | amdgpu_crtc->vsync_timer_enabled = AMDGPU_IRQ_STATE_DISABLE; |
|---|
| 253 | 253 | drm_crtc_helper_add(&amdgpu_crtc->base, &dce_virtual_crtc_helper_funcs); |
|---|
| 254 | 254 | |
|---|
| 255 | + hrtimer_init(&amdgpu_crtc->vblank_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); |
|---|
| 256 | + hrtimer_set_expires(&amdgpu_crtc->vblank_timer, DCE_VIRTUAL_VBLANK_PERIOD); |
|---|
| 257 | + amdgpu_crtc->vblank_timer.function = dce_virtual_vblank_timer_handle; |
|---|
| 258 | + hrtimer_start(&amdgpu_crtc->vblank_timer, |
|---|
| 259 | + DCE_VIRTUAL_VBLANK_PERIOD, HRTIMER_MODE_REL); |
|---|
| 255 | 260 | return 0; |
|---|
| 256 | 261 | } |
|---|
| 257 | 262 | |
|---|
| .. | .. |
|---|
| 271 | 276 | dce_virtual_encoder(struct drm_connector *connector) |
|---|
| 272 | 277 | { |
|---|
| 273 | 278 | struct drm_encoder *encoder; |
|---|
| 274 | | - int i; |
|---|
| 275 | 279 | |
|---|
| 276 | | - drm_connector_for_each_possible_encoder(connector, encoder, i) { |
|---|
| 280 | + drm_connector_for_each_possible_encoder(connector, encoder) { |
|---|
| 277 | 281 | if (encoder->encoder_type == DRM_MODE_ENCODER_VIRTUAL) |
|---|
| 278 | 282 | return encoder; |
|---|
| 279 | 283 | } |
|---|
| 280 | 284 | |
|---|
| 281 | 285 | /* pick the first one */ |
|---|
| 282 | | - drm_connector_for_each_possible_encoder(connector, encoder, i) |
|---|
| 286 | + drm_connector_for_each_possible_encoder(connector, encoder) |
|---|
| 283 | 287 | return encoder; |
|---|
| 284 | 288 | |
|---|
| 285 | 289 | return NULL; |
|---|
| .. | .. |
|---|
| 293 | 297 | static const struct mode_size { |
|---|
| 294 | 298 | int w; |
|---|
| 295 | 299 | int h; |
|---|
| 296 | | - } common_modes[17] = { |
|---|
| 300 | + } common_modes[21] = { |
|---|
| 297 | 301 | { 640, 480}, |
|---|
| 298 | 302 | { 720, 480}, |
|---|
| 299 | 303 | { 800, 600}, |
|---|
| .. | .. |
|---|
| 310 | 314 | {1680, 1050}, |
|---|
| 311 | 315 | {1600, 1200}, |
|---|
| 312 | 316 | {1920, 1080}, |
|---|
| 313 | | - {1920, 1200} |
|---|
| 317 | + {1920, 1200}, |
|---|
| 318 | + {4096, 3112}, |
|---|
| 319 | + {3656, 2664}, |
|---|
| 320 | + {3840, 2160}, |
|---|
| 321 | + {4096, 2160}, |
|---|
| 314 | 322 | }; |
|---|
| 315 | 323 | |
|---|
| 316 | | - for (i = 0; i < 17; i++) { |
|---|
| 324 | + for (i = 0; i < 21; i++) { |
|---|
| 317 | 325 | mode = drm_cvt_mode(dev, common_modes[i].w, common_modes[i].h, 60, false, false, false); |
|---|
| 318 | 326 | drm_mode_probed_add(connector, mode); |
|---|
| 319 | 327 | } |
|---|
| .. | .. |
|---|
| 372 | 380 | int r, i; |
|---|
| 373 | 381 | struct amdgpu_device *adev = (struct amdgpu_device *)handle; |
|---|
| 374 | 382 | |
|---|
| 375 | | - r = amdgpu_irq_add_id(adev, AMDGPU_IH_CLIENTID_LEGACY, VISLANDS30_IV_SRCID_SMU_DISP_TIMER2_TRIGGER, &adev->crtc_irq); |
|---|
| 383 | + r = amdgpu_irq_add_id(adev, AMDGPU_IRQ_CLIENTID_LEGACY, VISLANDS30_IV_SRCID_SMU_DISP_TIMER2_TRIGGER, &adev->crtc_irq); |
|---|
| 376 | 384 | if (r) |
|---|
| 377 | 385 | return r; |
|---|
| 378 | 386 | |
|---|
| 379 | | - adev->ddev->max_vblank_count = 0; |
|---|
| 387 | + adev_to_drm(adev)->max_vblank_count = 0; |
|---|
| 380 | 388 | |
|---|
| 381 | | - adev->ddev->mode_config.funcs = &amdgpu_mode_funcs; |
|---|
| 389 | + adev_to_drm(adev)->mode_config.funcs = &amdgpu_mode_funcs; |
|---|
| 382 | 390 | |
|---|
| 383 | | - adev->ddev->mode_config.max_width = 16384; |
|---|
| 384 | | - adev->ddev->mode_config.max_height = 16384; |
|---|
| 391 | + adev_to_drm(adev)->mode_config.max_width = 16384; |
|---|
| 392 | + adev_to_drm(adev)->mode_config.max_height = 16384; |
|---|
| 385 | 393 | |
|---|
| 386 | | - adev->ddev->mode_config.preferred_depth = 24; |
|---|
| 387 | | - adev->ddev->mode_config.prefer_shadow = 1; |
|---|
| 394 | + adev_to_drm(adev)->mode_config.preferred_depth = 24; |
|---|
| 395 | + adev_to_drm(adev)->mode_config.prefer_shadow = 1; |
|---|
| 388 | 396 | |
|---|
| 389 | | - adev->ddev->mode_config.fb_base = adev->gmc.aper_base; |
|---|
| 397 | + adev_to_drm(adev)->mode_config.fb_base = adev->gmc.aper_base; |
|---|
| 390 | 398 | |
|---|
| 391 | 399 | r = amdgpu_display_modeset_create_props(adev); |
|---|
| 392 | 400 | if (r) |
|---|
| 393 | 401 | return r; |
|---|
| 394 | 402 | |
|---|
| 395 | | - adev->ddev->mode_config.max_width = 16384; |
|---|
| 396 | | - adev->ddev->mode_config.max_height = 16384; |
|---|
| 403 | + adev_to_drm(adev)->mode_config.max_width = 16384; |
|---|
| 404 | + adev_to_drm(adev)->mode_config.max_height = 16384; |
|---|
| 397 | 405 | |
|---|
| 398 | 406 | /* allocate crtcs, encoders, connectors */ |
|---|
| 399 | 407 | for (i = 0; i < adev->mode_info.num_crtc; i++) { |
|---|
| .. | .. |
|---|
| 405 | 413 | return r; |
|---|
| 406 | 414 | } |
|---|
| 407 | 415 | |
|---|
| 408 | | - drm_kms_helper_poll_init(adev->ddev); |
|---|
| 416 | + drm_kms_helper_poll_init(adev_to_drm(adev)); |
|---|
| 409 | 417 | |
|---|
| 410 | 418 | adev->mode_info.mode_config_initialized = true; |
|---|
| 411 | 419 | return 0; |
|---|
| .. | .. |
|---|
| 417 | 425 | |
|---|
| 418 | 426 | kfree(adev->mode_info.bios_hardcoded_edid); |
|---|
| 419 | 427 | |
|---|
| 420 | | - drm_kms_helper_poll_fini(adev->ddev); |
|---|
| 428 | + drm_kms_helper_poll_fini(adev_to_drm(adev)); |
|---|
| 421 | 429 | |
|---|
| 422 | | - drm_mode_config_cleanup(adev->ddev); |
|---|
| 430 | + drm_mode_config_cleanup(adev_to_drm(adev)); |
|---|
| 423 | 431 | /* clear crtcs pointer to avoid dce irq finish routine access freed data */ |
|---|
| 424 | 432 | memset(adev->mode_info.crtcs, 0, sizeof(adev->mode_info.crtcs[0]) * AMDGPU_MAX_CRTCS); |
|---|
| 425 | 433 | adev->mode_info.mode_config_initialized = false; |
|---|
| .. | .. |
|---|
| 465 | 473 | #endif |
|---|
| 466 | 474 | /* no DCE */ |
|---|
| 467 | 475 | break; |
|---|
| 468 | | - case CHIP_VEGA10: |
|---|
| 469 | | - case CHIP_VEGA12: |
|---|
| 470 | | - case CHIP_VEGA20: |
|---|
| 471 | | - break; |
|---|
| 472 | 476 | default: |
|---|
| 473 | | - DRM_ERROR("Virtual display unsupported ASIC type: 0x%X\n", adev->asic_type); |
|---|
| 477 | + break; |
|---|
| 474 | 478 | } |
|---|
| 475 | 479 | return 0; |
|---|
| 476 | 480 | } |
|---|
| .. | .. |
|---|
| 482 | 486 | |
|---|
| 483 | 487 | for (i = 0; i<adev->mode_info.num_crtc; i++) |
|---|
| 484 | 488 | if (adev->mode_info.crtcs[i]) |
|---|
| 485 | | - dce_virtual_set_crtc_vblank_interrupt_state(adev, i, AMDGPU_IRQ_STATE_DISABLE); |
|---|
| 489 | + hrtimer_cancel(&adev->mode_info.crtcs[i]->vblank_timer); |
|---|
| 486 | 490 | |
|---|
| 487 | 491 | return 0; |
|---|
| 488 | 492 | } |
|---|
| .. | .. |
|---|
| 608 | 612 | if (!encoder) |
|---|
| 609 | 613 | return -ENOMEM; |
|---|
| 610 | 614 | encoder->possible_crtcs = 1 << index; |
|---|
| 611 | | - drm_encoder_init(adev->ddev, encoder, &dce_virtual_encoder_funcs, |
|---|
| 615 | + drm_encoder_init(adev_to_drm(adev), encoder, &dce_virtual_encoder_funcs, |
|---|
| 612 | 616 | DRM_MODE_ENCODER_VIRTUAL, NULL); |
|---|
| 613 | 617 | drm_encoder_helper_add(encoder, &dce_virtual_encoder_helper_funcs); |
|---|
| 614 | 618 | |
|---|
| .. | .. |
|---|
| 619 | 623 | } |
|---|
| 620 | 624 | |
|---|
| 621 | 625 | /* add a new connector */ |
|---|
| 622 | | - drm_connector_init(adev->ddev, connector, &dce_virtual_connector_funcs, |
|---|
| 626 | + drm_connector_init(adev_to_drm(adev), connector, &dce_virtual_connector_funcs, |
|---|
| 623 | 627 | DRM_MODE_CONNECTOR_VIRTUAL); |
|---|
| 624 | 628 | drm_connector_helper_add(connector, &dce_virtual_connector_helper_funcs); |
|---|
| 625 | 629 | connector->display_info.subpixel_order = SubPixelHorizontalRGB; |
|---|
| 626 | 630 | connector->interlace_allowed = false; |
|---|
| 627 | 631 | connector->doublescan_allowed = false; |
|---|
| 628 | | - drm_connector_register(connector); |
|---|
| 629 | 632 | |
|---|
| 630 | 633 | /* link them */ |
|---|
| 631 | 634 | drm_connector_attach_encoder(connector, encoder); |
|---|
| .. | .. |
|---|
| 649 | 652 | |
|---|
| 650 | 653 | static void dce_virtual_set_display_funcs(struct amdgpu_device *adev) |
|---|
| 651 | 654 | { |
|---|
| 652 | | - if (adev->mode_info.funcs == NULL) |
|---|
| 653 | | - adev->mode_info.funcs = &dce_virtual_display_funcs; |
|---|
| 655 | + adev->mode_info.funcs = &dce_virtual_display_funcs; |
|---|
| 654 | 656 | } |
|---|
| 655 | 657 | |
|---|
| 656 | 658 | static int dce_virtual_pageflip(struct amdgpu_device *adev, |
|---|
| .. | .. |
|---|
| 671 | 673 | if (amdgpu_crtc == NULL) |
|---|
| 672 | 674 | return 0; |
|---|
| 673 | 675 | |
|---|
| 674 | | - spin_lock_irqsave(&adev->ddev->event_lock, flags); |
|---|
| 676 | + spin_lock_irqsave(&adev_to_drm(adev)->event_lock, flags); |
|---|
| 675 | 677 | works = amdgpu_crtc->pflip_works; |
|---|
| 676 | 678 | if (amdgpu_crtc->pflip_status != AMDGPU_FLIP_SUBMITTED) { |
|---|
| 677 | 679 | DRM_DEBUG_DRIVER("amdgpu_crtc->pflip_status = %d != " |
|---|
| 678 | 680 | "AMDGPU_FLIP_SUBMITTED(%d)\n", |
|---|
| 679 | 681 | amdgpu_crtc->pflip_status, |
|---|
| 680 | 682 | AMDGPU_FLIP_SUBMITTED); |
|---|
| 681 | | - spin_unlock_irqrestore(&adev->ddev->event_lock, flags); |
|---|
| 683 | + spin_unlock_irqrestore(&adev_to_drm(adev)->event_lock, flags); |
|---|
| 682 | 684 | return 0; |
|---|
| 683 | 685 | } |
|---|
| 684 | 686 | |
|---|
| .. | .. |
|---|
| 690 | 692 | if (works->event) |
|---|
| 691 | 693 | drm_crtc_send_vblank_event(&amdgpu_crtc->base, works->event); |
|---|
| 692 | 694 | |
|---|
| 693 | | - spin_unlock_irqrestore(&adev->ddev->event_lock, flags); |
|---|
| 695 | + spin_unlock_irqrestore(&adev_to_drm(adev)->event_lock, flags); |
|---|
| 694 | 696 | |
|---|
| 695 | 697 | drm_crtc_vblank_put(&amdgpu_crtc->base); |
|---|
| 696 | | - schedule_work(&works->unpin_work); |
|---|
| 698 | + amdgpu_bo_unref(&works->old_abo); |
|---|
| 699 | + kfree(works->shared); |
|---|
| 700 | + kfree(works); |
|---|
| 697 | 701 | |
|---|
| 698 | 702 | return 0; |
|---|
| 699 | 703 | } |
|---|
| .. | .. |
|---|
| 703 | 707 | struct amdgpu_crtc *amdgpu_crtc = container_of(vblank_timer, |
|---|
| 704 | 708 | struct amdgpu_crtc, vblank_timer); |
|---|
| 705 | 709 | struct drm_device *ddev = amdgpu_crtc->base.dev; |
|---|
| 706 | | - struct amdgpu_device *adev = ddev->dev_private; |
|---|
| 710 | + struct amdgpu_device *adev = drm_to_adev(ddev); |
|---|
| 711 | + struct amdgpu_irq_src *source = adev->irq.client[AMDGPU_IRQ_CLIENTID_LEGACY].sources |
|---|
| 712 | + [VISLANDS30_IV_SRCID_SMU_DISP_TIMER2_TRIGGER]; |
|---|
| 713 | + int irq_type = amdgpu_display_crtc_idx_to_irq_type(adev, |
|---|
| 714 | + amdgpu_crtc->crtc_id); |
|---|
| 707 | 715 | |
|---|
| 708 | | - drm_handle_vblank(ddev, amdgpu_crtc->crtc_id); |
|---|
| 709 | | - dce_virtual_pageflip(adev, amdgpu_crtc->crtc_id); |
|---|
| 716 | + if (amdgpu_irq_enabled(adev, source, irq_type)) { |
|---|
| 717 | + drm_handle_vblank(ddev, amdgpu_crtc->crtc_id); |
|---|
| 718 | + dce_virtual_pageflip(adev, amdgpu_crtc->crtc_id); |
|---|
| 719 | + } |
|---|
| 710 | 720 | hrtimer_start(vblank_timer, DCE_VIRTUAL_VBLANK_PERIOD, |
|---|
| 711 | 721 | HRTIMER_MODE_REL); |
|---|
| 712 | 722 | |
|---|
| .. | .. |
|---|
| 720 | 730 | if (crtc >= adev->mode_info.num_crtc || !adev->mode_info.crtcs[crtc]) { |
|---|
| 721 | 731 | DRM_DEBUG("invalid crtc %d\n", crtc); |
|---|
| 722 | 732 | return; |
|---|
| 723 | | - } |
|---|
| 724 | | - |
|---|
| 725 | | - if (state && !adev->mode_info.crtcs[crtc]->vsync_timer_enabled) { |
|---|
| 726 | | - DRM_DEBUG("Enable software vsync timer\n"); |
|---|
| 727 | | - hrtimer_init(&adev->mode_info.crtcs[crtc]->vblank_timer, |
|---|
| 728 | | - CLOCK_MONOTONIC, HRTIMER_MODE_REL); |
|---|
| 729 | | - hrtimer_set_expires(&adev->mode_info.crtcs[crtc]->vblank_timer, |
|---|
| 730 | | - DCE_VIRTUAL_VBLANK_PERIOD); |
|---|
| 731 | | - adev->mode_info.crtcs[crtc]->vblank_timer.function = |
|---|
| 732 | | - dce_virtual_vblank_timer_handle; |
|---|
| 733 | | - hrtimer_start(&adev->mode_info.crtcs[crtc]->vblank_timer, |
|---|
| 734 | | - DCE_VIRTUAL_VBLANK_PERIOD, HRTIMER_MODE_REL); |
|---|
| 735 | | - } else if (!state && adev->mode_info.crtcs[crtc]->vsync_timer_enabled) { |
|---|
| 736 | | - DRM_DEBUG("Disable software vsync timer\n"); |
|---|
| 737 | | - hrtimer_cancel(&adev->mode_info.crtcs[crtc]->vblank_timer); |
|---|
| 738 | 733 | } |
|---|
| 739 | 734 | |
|---|
| 740 | 735 | adev->mode_info.crtcs[crtc]->vsync_timer_enabled = state; |
|---|