aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJesse Barnes <jbarnes@virtuousgeek.org>2009-03-31 17:11:15 -0400
committerEric Anholt <eric@anholt.net>2009-04-01 18:21:57 -0400
commit5ca58282089b11f64b911618036ee7676f12735b (patch)
tree4a53f11f1f0647ae28a4ba42269efc6b66d7b4fc
parent4a8df45894d26dc503013ea630927731c24be6b8 (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.c1
-rw-r--r--drivers/gpu/drm/i915/i915_dma.c7
-rw-r--r--drivers/gpu/drm/i915/i915_drv.h4
-rw-r--r--drivers/gpu/drm/i915/i915_irq.c67
-rw-r--r--drivers/gpu/drm/i915/i915_reg.h8
-rw-r--r--drivers/gpu/drm/i915/intel_crt.c4
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}
454EXPORT_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 */
189static 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
190irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) 199irqreturn_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
539int i915_driver_irq_postinstall(struct drm_device *dev) 568int 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))