diff options
Diffstat (limited to 'drivers/gpu')
-rw-r--r-- | drivers/gpu/drm/radeon/atombios_dp.c | 12 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/r100.c | 9 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/r600.c | 21 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon.h | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_connectors.c | 20 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_device.c | 9 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_display.c | 3 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_irq_kms.c | 21 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_mode.h | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/rs600.c | 9 |
10 files changed, 98 insertions, 10 deletions
diff --git a/drivers/gpu/drm/radeon/atombios_dp.c b/drivers/gpu/drm/radeon/atombios_dp.c index 784ba80afcb6..0d63c4436e7c 100644 --- a/drivers/gpu/drm/radeon/atombios_dp.c +++ b/drivers/gpu/drm/radeon/atombios_dp.c | |||
@@ -507,6 +507,18 @@ static bool atom_dp_get_link_status(struct radeon_connector *radeon_connector, | |||
507 | return true; | 507 | return true; |
508 | } | 508 | } |
509 | 509 | ||
510 | bool radeon_dp_needs_link_train(struct radeon_connector *radeon_connector) | ||
511 | { | ||
512 | struct radeon_connector_atom_dig *dig_connector = radeon_connector->con_priv; | ||
513 | u8 link_status[DP_LINK_STATUS_SIZE]; | ||
514 | |||
515 | if (!atom_dp_get_link_status(radeon_connector, link_status)) | ||
516 | return false; | ||
517 | if (dp_channel_eq_ok(link_status, dig_connector->dp_lane_count)) | ||
518 | return false; | ||
519 | return true; | ||
520 | } | ||
521 | |||
510 | static void dp_set_power(struct radeon_connector *radeon_connector, u8 power_state) | 522 | static void dp_set_power(struct radeon_connector *radeon_connector, u8 power_state) |
511 | { | 523 | { |
512 | struct radeon_connector_atom_dig *dig_connector = radeon_connector->con_priv; | 524 | struct radeon_connector_atom_dig *dig_connector = radeon_connector->con_priv; |
diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index 2b534c528aaf..b7baf16c11d7 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c | |||
@@ -289,6 +289,7 @@ static inline uint32_t r100_irq_ack(struct radeon_device *rdev) | |||
289 | int r100_irq_process(struct radeon_device *rdev) | 289 | int r100_irq_process(struct radeon_device *rdev) |
290 | { | 290 | { |
291 | uint32_t status, msi_rearm; | 291 | uint32_t status, msi_rearm; |
292 | bool queue_hotplug = false; | ||
292 | 293 | ||
293 | status = r100_irq_ack(rdev); | 294 | status = r100_irq_ack(rdev); |
294 | if (!status) { | 295 | if (!status) { |
@@ -310,13 +311,17 @@ int r100_irq_process(struct radeon_device *rdev) | |||
310 | drm_handle_vblank(rdev->ddev, 1); | 311 | drm_handle_vblank(rdev->ddev, 1); |
311 | } | 312 | } |
312 | if (status & RADEON_FP_DETECT_STAT) { | 313 | if (status & RADEON_FP_DETECT_STAT) { |
313 | DRM_INFO("HPD1\n"); | 314 | queue_hotplug = true; |
315 | DRM_DEBUG("HPD1\n"); | ||
314 | } | 316 | } |
315 | if (status & RADEON_FP2_DETECT_STAT) { | 317 | if (status & RADEON_FP2_DETECT_STAT) { |
316 | DRM_INFO("HPD2\n"); | 318 | queue_hotplug = true; |
319 | DRM_DEBUG("HPD2\n"); | ||
317 | } | 320 | } |
318 | status = r100_irq_ack(rdev); | 321 | status = r100_irq_ack(rdev); |
319 | } | 322 | } |
323 | if (queue_hotplug) | ||
324 | queue_work(rdev->wq, &rdev->hotplug_work); | ||
320 | if (rdev->msi_enabled) { | 325 | if (rdev->msi_enabled) { |
321 | switch (rdev->family) { | 326 | switch (rdev->family) { |
322 | case CHIP_RS400: | 327 | case CHIP_RS400: |
diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index c11715fb29c7..250ec3fe1a16 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c | |||
@@ -2674,6 +2674,7 @@ int r600_irq_process(struct radeon_device *rdev) | |||
2674 | u32 last_entry = rdev->ih.ring_size - 16; | 2674 | u32 last_entry = rdev->ih.ring_size - 16; |
2675 | u32 ring_index, disp_int, disp_int_cont, disp_int_cont2; | 2675 | u32 ring_index, disp_int, disp_int_cont, disp_int_cont2; |
2676 | unsigned long flags; | 2676 | unsigned long flags; |
2677 | bool queue_hotplug = false; | ||
2677 | 2678 | ||
2678 | DRM_DEBUG("r600_irq_process start: rptr %d, wptr %d\n", rptr, wptr); | 2679 | DRM_DEBUG("r600_irq_process start: rptr %d, wptr %d\n", rptr, wptr); |
2679 | 2680 | ||
@@ -2745,37 +2746,43 @@ restart_ih: | |||
2745 | case 0: | 2746 | case 0: |
2746 | if (disp_int & DC_HPD1_INTERRUPT) { | 2747 | if (disp_int & DC_HPD1_INTERRUPT) { |
2747 | disp_int &= ~DC_HPD1_INTERRUPT; | 2748 | disp_int &= ~DC_HPD1_INTERRUPT; |
2748 | DRM_INFO("IH: HPD1\n"); | 2749 | queue_hotplug = true; |
2750 | DRM_DEBUG("IH: HPD1\n"); | ||
2749 | } | 2751 | } |
2750 | break; | 2752 | break; |
2751 | case 1: | 2753 | case 1: |
2752 | if (disp_int & DC_HPD2_INTERRUPT) { | 2754 | if (disp_int & DC_HPD2_INTERRUPT) { |
2753 | disp_int &= ~DC_HPD2_INTERRUPT; | 2755 | disp_int &= ~DC_HPD2_INTERRUPT; |
2754 | DRM_INFO("IH: HPD2\n"); | 2756 | queue_hotplug = true; |
2757 | DRM_DEBUG("IH: HPD2\n"); | ||
2755 | } | 2758 | } |
2756 | break; | 2759 | break; |
2757 | case 4: | 2760 | case 4: |
2758 | if (disp_int_cont & DC_HPD3_INTERRUPT) { | 2761 | if (disp_int_cont & DC_HPD3_INTERRUPT) { |
2759 | disp_int_cont &= ~DC_HPD3_INTERRUPT; | 2762 | disp_int_cont &= ~DC_HPD3_INTERRUPT; |
2760 | DRM_INFO("IH: HPD3\n"); | 2763 | queue_hotplug = true; |
2764 | DRM_DEBUG("IH: HPD3\n"); | ||
2761 | } | 2765 | } |
2762 | break; | 2766 | break; |
2763 | case 5: | 2767 | case 5: |
2764 | if (disp_int_cont & DC_HPD4_INTERRUPT) { | 2768 | if (disp_int_cont & DC_HPD4_INTERRUPT) { |
2765 | disp_int_cont &= ~DC_HPD4_INTERRUPT; | 2769 | disp_int_cont &= ~DC_HPD4_INTERRUPT; |
2766 | DRM_INFO("IH: HPD4\n"); | 2770 | queue_hotplug = true; |
2771 | DRM_DEBUG("IH: HPD4\n"); | ||
2767 | } | 2772 | } |
2768 | break; | 2773 | break; |
2769 | case 10: | 2774 | case 10: |
2770 | if (disp_int_cont2 & DC_HPD5_INTERRUPT) { | 2775 | if (disp_int_cont2 & DC_HPD5_INTERRUPT) { |
2771 | disp_int_cont &= ~DC_HPD5_INTERRUPT; | 2776 | disp_int_cont &= ~DC_HPD5_INTERRUPT; |
2772 | DRM_INFO("IH: HPD5\n"); | 2777 | queue_hotplug = true; |
2778 | DRM_DEBUG("IH: HPD5\n"); | ||
2773 | } | 2779 | } |
2774 | break; | 2780 | break; |
2775 | case 12: | 2781 | case 12: |
2776 | if (disp_int_cont2 & DC_HPD6_INTERRUPT) { | 2782 | if (disp_int_cont2 & DC_HPD6_INTERRUPT) { |
2777 | disp_int_cont &= ~DC_HPD6_INTERRUPT; | 2783 | disp_int_cont &= ~DC_HPD6_INTERRUPT; |
2778 | DRM_INFO("IH: HPD6\n"); | 2784 | queue_hotplug = true; |
2785 | DRM_DEBUG("IH: HPD6\n"); | ||
2779 | } | 2786 | } |
2780 | break; | 2787 | break; |
2781 | default: | 2788 | default: |
@@ -2807,6 +2814,8 @@ restart_ih: | |||
2807 | wptr = r600_get_ih_wptr(rdev); | 2814 | wptr = r600_get_ih_wptr(rdev); |
2808 | if (wptr != rdev->ih.wptr) | 2815 | if (wptr != rdev->ih.wptr) |
2809 | goto restart_ih; | 2816 | goto restart_ih; |
2817 | if (queue_hotplug) | ||
2818 | queue_work(rdev->wq, &rdev->hotplug_work); | ||
2810 | rdev->ih.rptr = rptr; | 2819 | rdev->ih.rptr = rptr; |
2811 | WREG32(IH_RB_RPTR, rdev->ih.rptr); | 2820 | WREG32(IH_RB_RPTR, rdev->ih.rptr); |
2812 | spin_unlock_irqrestore(&rdev->ih.lock, flags); | 2821 | spin_unlock_irqrestore(&rdev->ih.lock, flags); |
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 29c6e0af3755..a15cf9ceb9a7 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h | |||
@@ -809,6 +809,8 @@ struct radeon_device { | |||
809 | struct r600_blit r600_blit; | 809 | struct r600_blit r600_blit; |
810 | int msi_enabled; /* msi enabled */ | 810 | int msi_enabled; /* msi enabled */ |
811 | struct r600_ih ih; /* r6/700 interrupt ring */ | 811 | struct r600_ih ih; /* r6/700 interrupt ring */ |
812 | struct workqueue_struct *wq; | ||
813 | struct work_struct hotplug_work; | ||
812 | }; | 814 | }; |
813 | 815 | ||
814 | int radeon_device_init(struct radeon_device *rdev, | 816 | int radeon_device_init(struct radeon_device *rdev, |
diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index 7328d1528a85..cfa2ebb259fe 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c | |||
@@ -40,6 +40,26 @@ radeon_atombios_connected_scratch_regs(struct drm_connector *connector, | |||
40 | struct drm_encoder *encoder, | 40 | struct drm_encoder *encoder, |
41 | bool connected); | 41 | bool connected); |
42 | 42 | ||
43 | void radeon_connector_hotplug(struct drm_connector *connector) | ||
44 | { | ||
45 | struct drm_device *dev = connector->dev; | ||
46 | struct radeon_device *rdev = dev->dev_private; | ||
47 | struct radeon_connector *radeon_connector = to_radeon_connector(connector); | ||
48 | |||
49 | if (radeon_connector->hpd.hpd != RADEON_HPD_NONE) | ||
50 | radeon_hpd_set_polarity(rdev, radeon_connector->hpd.hpd); | ||
51 | |||
52 | if (connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort) { | ||
53 | if (radeon_dp_getsinktype(radeon_connector) == CONNECTOR_OBJECT_ID_DISPLAYPORT) { | ||
54 | if (radeon_dp_needs_link_train(radeon_connector)) { | ||
55 | if (connector->encoder) | ||
56 | dp_link_train(connector->encoder, connector); | ||
57 | } | ||
58 | } | ||
59 | } | ||
60 | |||
61 | } | ||
62 | |||
43 | static void radeon_property_change_mode(struct drm_encoder *encoder) | 63 | static void radeon_property_change_mode(struct drm_encoder *encoder) |
44 | { | 64 | { |
45 | struct drm_crtc *crtc = encoder->crtc; | 65 | struct drm_crtc *crtc = encoder->crtc; |
diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index 60ee6a8b4f7f..7e55647f118e 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c | |||
@@ -570,6 +570,11 @@ int radeon_device_init(struct radeon_device *rdev, | |||
570 | rwlock_init(&rdev->fence_drv.lock); | 570 | rwlock_init(&rdev->fence_drv.lock); |
571 | INIT_LIST_HEAD(&rdev->gem.objects); | 571 | INIT_LIST_HEAD(&rdev->gem.objects); |
572 | 572 | ||
573 | /* setup workqueue */ | ||
574 | rdev->wq = create_workqueue("radeon"); | ||
575 | if (rdev->wq == NULL) | ||
576 | return -ENOMEM; | ||
577 | |||
573 | /* Set asic functions */ | 578 | /* Set asic functions */ |
574 | r = radeon_asic_init(rdev); | 579 | r = radeon_asic_init(rdev); |
575 | if (r) { | 580 | if (r) { |
@@ -643,6 +648,7 @@ void radeon_device_fini(struct radeon_device *rdev) | |||
643 | DRM_INFO("radeon: finishing device.\n"); | 648 | DRM_INFO("radeon: finishing device.\n"); |
644 | rdev->shutdown = true; | 649 | rdev->shutdown = true; |
645 | radeon_fini(rdev); | 650 | radeon_fini(rdev); |
651 | destroy_workqueue(rdev->wq); | ||
646 | vga_client_register(rdev->pdev, NULL, NULL, NULL); | 652 | vga_client_register(rdev->pdev, NULL, NULL, NULL); |
647 | iounmap(rdev->rmmio); | 653 | iounmap(rdev->rmmio); |
648 | rdev->rmmio = NULL; | 654 | rdev->rmmio = NULL; |
@@ -689,6 +695,7 @@ int radeon_suspend_kms(struct drm_device *dev, pm_message_t state) | |||
689 | radeon_save_bios_scratch_regs(rdev); | 695 | radeon_save_bios_scratch_regs(rdev); |
690 | 696 | ||
691 | radeon_suspend(rdev); | 697 | radeon_suspend(rdev); |
698 | radeon_hpd_fini(rdev); | ||
692 | /* evict remaining vram memory */ | 699 | /* evict remaining vram memory */ |
693 | radeon_bo_evict_vram(rdev); | 700 | radeon_bo_evict_vram(rdev); |
694 | 701 | ||
@@ -723,6 +730,8 @@ int radeon_resume_kms(struct drm_device *dev) | |||
723 | fb_set_suspend(rdev->fbdev_info, 0); | 730 | fb_set_suspend(rdev->fbdev_info, 0); |
724 | release_console_sem(); | 731 | release_console_sem(); |
725 | 732 | ||
733 | /* reset hpd state */ | ||
734 | radeon_hpd_init(rdev); | ||
726 | /* blat the mode back in */ | 735 | /* blat the mode back in */ |
727 | drm_helper_resume_force_mode(dev); | 736 | drm_helper_resume_force_mode(dev); |
728 | return 0; | 737 | return 0; |
diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index d4f4fb1c54c7..c115f2e442eb 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c | |||
@@ -741,6 +741,8 @@ int radeon_modeset_init(struct radeon_device *rdev) | |||
741 | if (!ret) { | 741 | if (!ret) { |
742 | return ret; | 742 | return ret; |
743 | } | 743 | } |
744 | /* initialize hpd */ | ||
745 | radeon_hpd_init(rdev); | ||
744 | drm_helper_initial_config(rdev->ddev); | 746 | drm_helper_initial_config(rdev->ddev); |
745 | return 0; | 747 | return 0; |
746 | } | 748 | } |
@@ -748,6 +750,7 @@ int radeon_modeset_init(struct radeon_device *rdev) | |||
748 | void radeon_modeset_fini(struct radeon_device *rdev) | 750 | void radeon_modeset_fini(struct radeon_device *rdev) |
749 | { | 751 | { |
750 | if (rdev->mode_info.mode_config_initialized) { | 752 | if (rdev->mode_info.mode_config_initialized) { |
753 | radeon_hpd_fini(rdev); | ||
751 | drm_mode_config_cleanup(rdev->ddev); | 754 | drm_mode_config_cleanup(rdev->ddev); |
752 | rdev->mode_info.mode_config_initialized = false; | 755 | rdev->mode_info.mode_config_initialized = false; |
753 | } | 756 | } |
diff --git a/drivers/gpu/drm/radeon/radeon_irq_kms.c b/drivers/gpu/drm/radeon/radeon_irq_kms.c index 26789970c5cf..9223296fe37b 100644 --- a/drivers/gpu/drm/radeon/radeon_irq_kms.c +++ b/drivers/gpu/drm/radeon/radeon_irq_kms.c | |||
@@ -39,11 +39,32 @@ irqreturn_t radeon_driver_irq_handler_kms(DRM_IRQ_ARGS) | |||
39 | return radeon_irq_process(rdev); | 39 | return radeon_irq_process(rdev); |
40 | } | 40 | } |
41 | 41 | ||
42 | /* | ||
43 | * Handle hotplug events outside the interrupt handler proper. | ||
44 | */ | ||
45 | static void radeon_hotplug_work_func(struct work_struct *work) | ||
46 | { | ||
47 | struct radeon_device *rdev = container_of(work, struct radeon_device, | ||
48 | hotplug_work); | ||
49 | struct drm_device *dev = rdev->ddev; | ||
50 | struct drm_mode_config *mode_config = &dev->mode_config; | ||
51 | struct drm_connector *connector; | ||
52 | |||
53 | if (mode_config->num_connector) { | ||
54 | list_for_each_entry(connector, &mode_config->connector_list, head) | ||
55 | radeon_connector_hotplug(connector); | ||
56 | } | ||
57 | /* Just fire off a uevent and let userspace tell us what to do */ | ||
58 | drm_sysfs_hotplug_event(dev); | ||
59 | } | ||
60 | |||
42 | void radeon_driver_irq_preinstall_kms(struct drm_device *dev) | 61 | void radeon_driver_irq_preinstall_kms(struct drm_device *dev) |
43 | { | 62 | { |
44 | struct radeon_device *rdev = dev->dev_private; | 63 | struct radeon_device *rdev = dev->dev_private; |
45 | unsigned i; | 64 | unsigned i; |
46 | 65 | ||
66 | INIT_WORK(&rdev->hotplug_work, radeon_hotplug_work_func); | ||
67 | |||
47 | /* Disable *all* interrupts */ | 68 | /* Disable *all* interrupts */ |
48 | rdev->irq.sw_int = false; | 69 | rdev->irq.sw_int = false; |
49 | for (i = 0; i < 2; i++) { | 70 | for (i = 0; i < 2; i++) { |
diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index 61b90343f794..15ec7ca18a95 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h | |||
@@ -392,6 +392,8 @@ struct radeon_framebuffer { | |||
392 | struct drm_gem_object *obj; | 392 | struct drm_gem_object *obj; |
393 | }; | 393 | }; |
394 | 394 | ||
395 | extern void radeon_connector_hotplug(struct drm_connector *connector); | ||
396 | extern bool radeon_dp_needs_link_train(struct radeon_connector *radeon_connector); | ||
395 | extern int radeon_dp_mode_valid_helper(struct radeon_connector *radeon_connector, | 397 | extern int radeon_dp_mode_valid_helper(struct radeon_connector *radeon_connector, |
396 | struct drm_display_mode *mode); | 398 | struct drm_display_mode *mode); |
397 | extern void radeon_dp_set_link_config(struct drm_connector *connector, | 399 | extern void radeon_dp_set_link_config(struct drm_connector *connector, |
diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c index 6364ba1d4153..fd5ab01f6ad1 100644 --- a/drivers/gpu/drm/radeon/rs600.c +++ b/drivers/gpu/drm/radeon/rs600.c | |||
@@ -388,6 +388,7 @@ int rs600_irq_process(struct radeon_device *rdev) | |||
388 | { | 388 | { |
389 | uint32_t status, msi_rearm; | 389 | uint32_t status, msi_rearm; |
390 | uint32_t r500_disp_int; | 390 | uint32_t r500_disp_int; |
391 | bool queue_hotplug = false; | ||
391 | 392 | ||
392 | status = rs600_irq_ack(rdev, &r500_disp_int); | 393 | status = rs600_irq_ack(rdev, &r500_disp_int); |
393 | if (!status && !r500_disp_int) { | 394 | if (!status && !r500_disp_int) { |
@@ -403,13 +404,17 @@ int rs600_irq_process(struct radeon_device *rdev) | |||
403 | if (G_007EDC_LB_D2_VBLANK_INTERRUPT(r500_disp_int)) | 404 | if (G_007EDC_LB_D2_VBLANK_INTERRUPT(r500_disp_int)) |
404 | drm_handle_vblank(rdev->ddev, 1); | 405 | drm_handle_vblank(rdev->ddev, 1); |
405 | if (G_007EDC_DC_HOT_PLUG_DETECT1_INTERRUPT(r500_disp_int)) { | 406 | if (G_007EDC_DC_HOT_PLUG_DETECT1_INTERRUPT(r500_disp_int)) { |
406 | DRM_INFO("HPD1\n"); | 407 | queue_hotplug = true; |
408 | DRM_DEBUG("HPD1\n"); | ||
407 | } | 409 | } |
408 | if (G_007EDC_DC_HOT_PLUG_DETECT2_INTERRUPT(r500_disp_int)) { | 410 | if (G_007EDC_DC_HOT_PLUG_DETECT2_INTERRUPT(r500_disp_int)) { |
409 | DRM_INFO("HPD2\n"); | 411 | queue_hotplug = true; |
412 | DRM_DEBUG("HPD2\n"); | ||
410 | } | 413 | } |
411 | status = rs600_irq_ack(rdev, &r500_disp_int); | 414 | status = rs600_irq_ack(rdev, &r500_disp_int); |
412 | } | 415 | } |
416 | if (queue_hotplug) | ||
417 | queue_work(rdev->wq, &rdev->hotplug_work); | ||
413 | if (rdev->msi_enabled) { | 418 | if (rdev->msi_enabled) { |
414 | switch (rdev->family) { | 419 | switch (rdev->family) { |
415 | case CHIP_RS600: | 420 | case CHIP_RS600: |