diff options
author | Jesse Barnes <jbarnes@virtuousgeek.org> | 2009-03-31 17:11:15 -0400 |
---|---|---|
committer | Eric Anholt <eric@anholt.net> | 2009-04-01 18:21:57 -0400 |
commit | 5ca58282089b11f64b911618036ee7676f12735b (patch) | |
tree | 4a53f11f1f0647ae28a4ba42269efc6b66d7b4fc | |
parent | 4a8df45894d26dc503013ea630927731c24be6b8 (diff) |
drm/i915: add VGA hotplug support for 945+
Add VGA port hotplug detection to the i915 driver. When KMS is enabled,
plugging in or removing a VGA cable from the VGA connector will
generate a uevent, which indicates to userspace that it should re-probe
outputs on this device (to determine modes, etc.).
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
[anholt: dropped extra PORT_HOTPLUG_STAT clear with ack from jbarnes]
Signed-off-by: Eric Anholt <eric@anholt.net>
-rw-r--r-- | drivers/gpu/drm/drm_sysfs.c | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_dma.c | 7 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_drv.h | 4 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_irq.c | 67 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_reg.h | 8 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_crt.c | 4 |
6 files changed, 77 insertions, 14 deletions
diff --git a/drivers/gpu/drm/drm_sysfs.c b/drivers/gpu/drm/drm_sysfs.c index 5de573a981cb..bc0c6849360c 100644 --- a/drivers/gpu/drm/drm_sysfs.c +++ b/drivers/gpu/drm/drm_sysfs.c | |||
@@ -451,6 +451,7 @@ void drm_sysfs_hotplug_event(struct drm_device *dev) | |||
451 | 451 | ||
452 | kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, envp); | 452 | kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, envp); |
453 | } | 453 | } |
454 | EXPORT_SYMBOL(drm_sysfs_hotplug_event); | ||
454 | 455 | ||
455 | /** | 456 | /** |
456 | * drm_sysfs_device_add - adds a class device to sysfs for a character driver | 457 | * drm_sysfs_device_add - adds a class device to sysfs for a character driver |
diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 8ce57f9b11fa..0b9984ffed12 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c | |||
@@ -1030,13 +1030,6 @@ static int i915_load_modeset_init(struct drm_device *dev) | |||
1030 | if (ret) | 1030 | if (ret) |
1031 | goto destroy_ringbuffer; | 1031 | goto destroy_ringbuffer; |
1032 | 1032 | ||
1033 | /* FIXME: re-add hotplug support */ | ||
1034 | #if 0 | ||
1035 | ret = drm_hotplug_init(dev); | ||
1036 | if (ret) | ||
1037 | goto destroy_ringbuffer; | ||
1038 | #endif | ||
1039 | |||
1040 | /* Always safe in the mode setting case. */ | 1033 | /* Always safe in the mode setting case. */ |
1041 | /* FIXME: do pre/post-mode set stuff in core KMS code */ | 1034 | /* FIXME: do pre/post-mode set stuff in core KMS code */ |
1042 | dev->vblank_disable_allowed = 1; | 1035 | dev->vblank_disable_allowed = 1; |
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index c1685d0c704f..c0f48bb366bf 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h | |||
@@ -159,6 +159,9 @@ typedef struct drm_i915_private { | |||
159 | u32 irq_mask_reg; | 159 | u32 irq_mask_reg; |
160 | u32 pipestat[2]; | 160 | u32 pipestat[2]; |
161 | 161 | ||
162 | u32 hotplug_supported_mask; | ||
163 | struct work_struct hotplug_work; | ||
164 | |||
162 | int tex_lru_log_granularity; | 165 | int tex_lru_log_granularity; |
163 | int allow_batchbuffer; | 166 | int allow_batchbuffer; |
164 | struct mem_block *agp_heap; | 167 | struct mem_block *agp_heap; |
@@ -810,6 +813,7 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller); | |||
810 | #define HAS_128_BYTE_Y_TILING(dev) (IS_I9XX(dev) && !(IS_I915G(dev) || \ | 813 | #define HAS_128_BYTE_Y_TILING(dev) (IS_I9XX(dev) && !(IS_I915G(dev) || \ |
811 | IS_I915GM(dev))) | 814 | IS_I915GM(dev))) |
812 | #define SUPPORTS_INTEGRATED_HDMI(dev) (IS_G4X(dev)) | 815 | #define SUPPORTS_INTEGRATED_HDMI(dev) (IS_G4X(dev)) |
816 | #define I915_HAS_HOTPLUG(dev) (IS_I945G(dev) || IS_I945GM(dev) || IS_I965G(dev)) | ||
813 | 817 | ||
814 | #define PRIMARY_RINGBUFFER_SIZE (128*1024) | 818 | #define PRIMARY_RINGBUFFER_SIZE (128*1024) |
815 | 819 | ||
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 87b6b603469e..ee7ce7b78cf7 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c | |||
@@ -48,10 +48,6 @@ | |||
48 | /** Interrupts that we mask and unmask at runtime. */ | 48 | /** Interrupts that we mask and unmask at runtime. */ |
49 | #define I915_INTERRUPT_ENABLE_VAR (I915_USER_INTERRUPT) | 49 | #define I915_INTERRUPT_ENABLE_VAR (I915_USER_INTERRUPT) |
50 | 50 | ||
51 | /** These are all of the interrupts used by the driver */ | ||
52 | #define I915_INTERRUPT_ENABLE_MASK (I915_INTERRUPT_ENABLE_FIX | \ | ||
53 | I915_INTERRUPT_ENABLE_VAR) | ||
54 | |||
55 | #define I915_PIPE_VBLANK_STATUS (PIPE_START_VBLANK_INTERRUPT_STATUS |\ | 51 | #define I915_PIPE_VBLANK_STATUS (PIPE_START_VBLANK_INTERRUPT_STATUS |\ |
56 | PIPE_VBLANK_INTERRUPT_STATUS) | 52 | PIPE_VBLANK_INTERRUPT_STATUS) |
57 | 53 | ||
@@ -187,6 +183,19 @@ u32 gm45_get_vblank_counter(struct drm_device *dev, int pipe) | |||
187 | return I915_READ(reg); | 183 | return I915_READ(reg); |
188 | } | 184 | } |
189 | 185 | ||
186 | /* | ||
187 | * Handle hotplug events outside the interrupt handler proper. | ||
188 | */ | ||
189 | static void i915_hotplug_work_func(struct work_struct *work) | ||
190 | { | ||
191 | drm_i915_private_t *dev_priv = container_of(work, drm_i915_private_t, | ||
192 | hotplug_work); | ||
193 | struct drm_device *dev = dev_priv->dev; | ||
194 | |||
195 | /* Just fire off a uevent and let userspace tell us what to do */ | ||
196 | drm_sysfs_hotplug_event(dev); | ||
197 | } | ||
198 | |||
190 | irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) | 199 | irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) |
191 | { | 200 | { |
192 | struct drm_device *dev = (struct drm_device *) arg; | 201 | struct drm_device *dev = (struct drm_device *) arg; |
@@ -244,6 +253,20 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) | |||
244 | 253 | ||
245 | ret = IRQ_HANDLED; | 254 | ret = IRQ_HANDLED; |
246 | 255 | ||
256 | /* Consume port. Then clear IIR or we'll miss events */ | ||
257 | if ((I915_HAS_HOTPLUG(dev)) && | ||
258 | (iir & I915_DISPLAY_PORT_INTERRUPT)) { | ||
259 | u32 hotplug_status = I915_READ(PORT_HOTPLUG_STAT); | ||
260 | |||
261 | DRM_DEBUG("hotplug event received, stat 0x%08x\n", | ||
262 | hotplug_status); | ||
263 | if (hotplug_status & dev_priv->hotplug_supported_mask) | ||
264 | schedule_work(&dev_priv->hotplug_work); | ||
265 | |||
266 | I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status); | ||
267 | I915_READ(PORT_HOTPLUG_STAT); | ||
268 | } | ||
269 | |||
247 | I915_WRITE(IIR, iir); | 270 | I915_WRITE(IIR, iir); |
248 | new_iir = I915_READ(IIR); /* Flush posted writes */ | 271 | new_iir = I915_READ(IIR); /* Flush posted writes */ |
249 | 272 | ||
@@ -528,17 +551,24 @@ void i915_driver_irq_preinstall(struct drm_device * dev) | |||
528 | 551 | ||
529 | atomic_set(&dev_priv->irq_received, 0); | 552 | atomic_set(&dev_priv->irq_received, 0); |
530 | 553 | ||
554 | if (I915_HAS_HOTPLUG(dev)) { | ||
555 | I915_WRITE(PORT_HOTPLUG_EN, 0); | ||
556 | I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT)); | ||
557 | } | ||
558 | |||
531 | I915_WRITE(HWSTAM, 0xeffe); | 559 | I915_WRITE(HWSTAM, 0xeffe); |
532 | I915_WRITE(PIPEASTAT, 0); | 560 | I915_WRITE(PIPEASTAT, 0); |
533 | I915_WRITE(PIPEBSTAT, 0); | 561 | I915_WRITE(PIPEBSTAT, 0); |
534 | I915_WRITE(IMR, 0xffffffff); | 562 | I915_WRITE(IMR, 0xffffffff); |
535 | I915_WRITE(IER, 0x0); | 563 | I915_WRITE(IER, 0x0); |
536 | (void) I915_READ(IER); | 564 | (void) I915_READ(IER); |
565 | INIT_WORK(&dev_priv->hotplug_work, i915_hotplug_work_func); | ||
537 | } | 566 | } |
538 | 567 | ||
539 | int i915_driver_irq_postinstall(struct drm_device *dev) | 568 | int i915_driver_irq_postinstall(struct drm_device *dev) |
540 | { | 569 | { |
541 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; | 570 | drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; |
571 | u32 enable_mask = I915_INTERRUPT_ENABLE_FIX | I915_INTERRUPT_ENABLE_VAR; | ||
542 | 572 | ||
543 | dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B; | 573 | dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B; |
544 | 574 | ||
@@ -550,13 +580,35 @@ int i915_driver_irq_postinstall(struct drm_device *dev) | |||
550 | dev_priv->pipestat[0] = 0; | 580 | dev_priv->pipestat[0] = 0; |
551 | dev_priv->pipestat[1] = 0; | 581 | dev_priv->pipestat[1] = 0; |
552 | 582 | ||
583 | if (I915_HAS_HOTPLUG(dev)) { | ||
584 | u32 hotplug_en = I915_READ(PORT_HOTPLUG_EN); | ||
585 | |||
586 | /* Leave other bits alone */ | ||
587 | hotplug_en |= HOTPLUG_EN_MASK; | ||
588 | I915_WRITE(PORT_HOTPLUG_EN, hotplug_en); | ||
589 | |||
590 | dev_priv->hotplug_supported_mask = CRT_HOTPLUG_INT_STATUS | | ||
591 | TV_HOTPLUG_INT_STATUS | SDVOC_HOTPLUG_INT_STATUS | | ||
592 | SDVOB_HOTPLUG_INT_STATUS; | ||
593 | if (IS_G4X(dev)) { | ||
594 | dev_priv->hotplug_supported_mask |= | ||
595 | HDMIB_HOTPLUG_INT_STATUS | | ||
596 | HDMIC_HOTPLUG_INT_STATUS | | ||
597 | HDMID_HOTPLUG_INT_STATUS; | ||
598 | } | ||
599 | /* Enable in IER... */ | ||
600 | enable_mask |= I915_DISPLAY_PORT_INTERRUPT; | ||
601 | /* and unmask in IMR */ | ||
602 | i915_enable_irq(dev_priv, I915_DISPLAY_PORT_INTERRUPT); | ||
603 | } | ||
604 | |||
553 | /* Disable pipe interrupt enables, clear pending pipe status */ | 605 | /* Disable pipe interrupt enables, clear pending pipe status */ |
554 | I915_WRITE(PIPEASTAT, I915_READ(PIPEASTAT) & 0x8000ffff); | 606 | I915_WRITE(PIPEASTAT, I915_READ(PIPEASTAT) & 0x8000ffff); |
555 | I915_WRITE(PIPEBSTAT, I915_READ(PIPEBSTAT) & 0x8000ffff); | 607 | I915_WRITE(PIPEBSTAT, I915_READ(PIPEBSTAT) & 0x8000ffff); |
556 | /* Clear pending interrupt status */ | 608 | /* Clear pending interrupt status */ |
557 | I915_WRITE(IIR, I915_READ(IIR)); | 609 | I915_WRITE(IIR, I915_READ(IIR)); |
558 | 610 | ||
559 | I915_WRITE(IER, I915_INTERRUPT_ENABLE_MASK); | 611 | I915_WRITE(IER, enable_mask); |
560 | I915_WRITE(IMR, dev_priv->irq_mask_reg); | 612 | I915_WRITE(IMR, dev_priv->irq_mask_reg); |
561 | (void) I915_READ(IER); | 613 | (void) I915_READ(IER); |
562 | 614 | ||
@@ -575,6 +627,11 @@ void i915_driver_irq_uninstall(struct drm_device * dev) | |||
575 | 627 | ||
576 | dev_priv->vblank_pipe = 0; | 628 | dev_priv->vblank_pipe = 0; |
577 | 629 | ||
630 | if (I915_HAS_HOTPLUG(dev)) { | ||
631 | I915_WRITE(PORT_HOTPLUG_EN, 0); | ||
632 | I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT)); | ||
633 | } | ||
634 | |||
578 | I915_WRITE(HWSTAM, 0xffffffff); | 635 | I915_WRITE(HWSTAM, 0xffffffff); |
579 | I915_WRITE(PIPEASTAT, 0); | 636 | I915_WRITE(PIPEASTAT, 0); |
580 | I915_WRITE(PIPEBSTAT, 0); | 637 | I915_WRITE(PIPEBSTAT, 0); |
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 83357b09e546..e805b590ae71 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h | |||
@@ -651,6 +651,14 @@ | |||
651 | #define CRT_HOTPLUG_DETECT_VOLTAGE_325MV (0 << 2) | 651 | #define CRT_HOTPLUG_DETECT_VOLTAGE_325MV (0 << 2) |
652 | #define CRT_HOTPLUG_DETECT_VOLTAGE_475MV (1 << 2) | 652 | #define CRT_HOTPLUG_DETECT_VOLTAGE_475MV (1 << 2) |
653 | #define CRT_HOTPLUG_MASK (0x3fc) /* Bits 9-2 */ | 653 | #define CRT_HOTPLUG_MASK (0x3fc) /* Bits 9-2 */ |
654 | #define CRT_FORCE_HOTPLUG_MASK 0xfffffe1f | ||
655 | #define HOTPLUG_EN_MASK (HDMIB_HOTPLUG_INT_EN | \ | ||
656 | HDMIC_HOTPLUG_INT_EN | \ | ||
657 | HDMID_HOTPLUG_INT_EN | \ | ||
658 | SDVOB_HOTPLUG_INT_EN | \ | ||
659 | SDVOC_HOTPLUG_INT_EN | \ | ||
660 | TV_HOTPLUG_INT_EN | \ | ||
661 | CRT_HOTPLUG_INT_EN) | ||
654 | 662 | ||
655 | 663 | ||
656 | #define PORT_HOTPLUG_STAT 0x61114 | 664 | #define PORT_HOTPLUG_STAT 0x61114 |
diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index 2b6d44381c31..9bdd959260a5 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c | |||
@@ -41,7 +41,7 @@ static void intel_crt_dpms(struct drm_encoder *encoder, int mode) | |||
41 | 41 | ||
42 | temp = I915_READ(ADPA); | 42 | temp = I915_READ(ADPA); |
43 | temp &= ~(ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE); | 43 | temp &= ~(ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE); |
44 | temp &= ~ADPA_DAC_ENABLE; | 44 | temp |= ADPA_DAC_ENABLE; |
45 | 45 | ||
46 | switch(mode) { | 46 | switch(mode) { |
47 | case DRM_MODE_DPMS_ON: | 47 | case DRM_MODE_DPMS_ON: |
@@ -158,7 +158,7 @@ static bool intel_crt_detect_hotplug(struct drm_connector *connector) | |||
158 | else | 158 | else |
159 | tries = 1; | 159 | tries = 1; |
160 | hotplug_en = I915_READ(PORT_HOTPLUG_EN); | 160 | hotplug_en = I915_READ(PORT_HOTPLUG_EN); |
161 | hotplug_en &= ~(CRT_HOTPLUG_MASK); | 161 | hotplug_en &= CRT_FORCE_HOTPLUG_MASK; |
162 | hotplug_en |= CRT_HOTPLUG_FORCE_DETECT; | 162 | hotplug_en |= CRT_HOTPLUG_FORCE_DETECT; |
163 | 163 | ||
164 | if (IS_GM45(dev)) | 164 | if (IS_GM45(dev)) |