aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu
diff options
context:
space:
mode:
authorAlex Deucher <alexdeucher@gmail.com>2009-12-04 16:56:37 -0500
committerDave Airlie <airlied@redhat.com>2009-12-07 19:48:22 -0500
commitd4877cf2293f5463f531769fd12300cb3417c778 (patch)
treeee9533aaf9fac0bbec859cf5d888fa73a71875bd /drivers/gpu
parent429770b3e39999c4d025fbcb9959502adc3989d8 (diff)
drm/radeon/kms: enable hpd support
This enabled interrupt driven hpd support for all radeon chips. Assuming the hpd pin is wired up correctly, the driver will generate uevents on digital monitor connect and disconnect and retrain DP monitors automatically. Signed-off-by: Alex Deucher <alexdeucher@gmail.com> Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/gpu')
-rw-r--r--drivers/gpu/drm/radeon/atombios_dp.c12
-rw-r--r--drivers/gpu/drm/radeon/r100.c9
-rw-r--r--drivers/gpu/drm/radeon/r600.c21
-rw-r--r--drivers/gpu/drm/radeon/radeon.h2
-rw-r--r--drivers/gpu/drm/radeon/radeon_connectors.c20
-rw-r--r--drivers/gpu/drm/radeon/radeon_device.c9
-rw-r--r--drivers/gpu/drm/radeon/radeon_display.c3
-rw-r--r--drivers/gpu/drm/radeon/radeon_irq_kms.c21
-rw-r--r--drivers/gpu/drm/radeon/radeon_mode.h2
-rw-r--r--drivers/gpu/drm/radeon/rs600.c9
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
510bool 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
510static void dp_set_power(struct radeon_connector *radeon_connector, u8 power_state) 522static 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)
289int r100_irq_process(struct radeon_device *rdev) 289int 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
814int radeon_device_init(struct radeon_device *rdev, 816int 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
43void 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
43static void radeon_property_change_mode(struct drm_encoder *encoder) 63static 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)
748void radeon_modeset_fini(struct radeon_device *rdev) 750void 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 */
45static 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
42void radeon_driver_irq_preinstall_kms(struct drm_device *dev) 61void 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
395extern void radeon_connector_hotplug(struct drm_connector *connector);
396extern bool radeon_dp_needs_link_train(struct radeon_connector *radeon_connector);
395extern int radeon_dp_mode_valid_helper(struct radeon_connector *radeon_connector, 397extern int radeon_dp_mode_valid_helper(struct radeon_connector *radeon_connector,
396 struct drm_display_mode *mode); 398 struct drm_display_mode *mode);
397extern void radeon_dp_set_link_config(struct drm_connector *connector, 399extern 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: