From e239882b1e90cba0297118ec7dc432bea06b0bd0 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Tue, 4 Dec 2007 15:36:36 +0100 Subject: Modesetting Hotplug --- shared-core/i915_drv.h | 2 + shared-core/i915_init.c | 40 ++++---- shared-core/i915_irq.c | 238 +++++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 245 insertions(+), 35 deletions(-) (limited to 'shared-core') diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h index d9e86de9..45b7786a 100644 --- a/shared-core/i915_drv.h +++ b/shared-core/i915_drv.h @@ -135,6 +135,8 @@ struct drm_i915_private { uint32_t irq_enable_reg; int irq_enabled; + struct workqueue_struct *wq; + #ifdef I915_HAVE_FENCE uint32_t flush_sequence; uint32_t flush_flags; diff --git a/shared-core/i915_init.c b/shared-core/i915_init.c index 3b43c722..588cd17e 100644 --- a/shared-core/i915_init.c +++ b/shared-core/i915_init.c @@ -30,7 +30,7 @@ int i915_probe_agp(struct pci_dev *pdev, unsigned long *aperture_size, u16 tmp = 0; unsigned long overhead; - bridge_dev = pci_get_bus_and_slot(0, PCI_DEVFN(0,0)); + bridge_dev = pci_find_slot(0, PCI_DEVFN(0,0)); if (!bridge_dev) { DRM_ERROR("bridge device not found\n"); return -1; @@ -249,9 +249,20 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) } DRM_DEBUG("Enabled hardware status page\n"); + dev_priv->wq = create_singlethread_workqueue("i915"); + if (dev_priv == 0) { + DRM_DEBUG("Error\n"); + } + + intel_modeset_init(dev); drm_initial_config(dev, false); + drm_mm_print(&dev->bm.man[DRM_BO_MEM_VRAM].manager, "VRAM"); + drm_mm_print(&dev->bm.man[DRM_BO_MEM_TT].manager, "TT"); + + drm_irq_install(dev); + return 0; } @@ -259,9 +270,15 @@ int i915_driver_unload(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; + I915_WRITE(LP_RING + RING_LEN, 0); + + intel_modeset_cleanup(dev); + +#if 0 if (dev_priv->ring.virtual_start) { drm_core_ioremapfree(&dev_priv->ring.map, dev); } +#endif if (dev_priv->status_page_dmah) { drm_pci_free(dev, dev_priv->status_page_dmah); @@ -278,10 +295,6 @@ int i915_driver_unload(struct drm_device *dev) I915_WRITE(I915REG_HWS_PGA, 0x1ffff000); } - I915_WRITE(LP_RING + RING_LEN, 0); - - intel_modeset_cleanup(dev); - drm_mem_reg_iounmap(dev, &dev_priv->ring_buffer->mem, dev_priv->ring.virtual_start); @@ -310,20 +323,3 @@ int i915_driver_unload(struct drm_device *dev) dev->dev_private = NULL; return 0; } - -void i915_driver_lastclose(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - - i915_do_cleanup_pageflip(dev); - //i915_mem_takedown(&(dev_priv->agp_heap)); - i915_dma_cleanup(dev); -} - -void i915_driver_preclose(struct drm_device *dev, struct drm_file *filp) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - - //i915_mem_release(dev, filp, dev_priv->agp_heap); -} - diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index 4312eae2..4508d146 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -31,6 +31,8 @@ #include "i915_drm.h" #include "i915_drv.h" +#include "intel_drv.h" + #define USER_INT_FLAG (1<<1) #define VSYNC_PIPEB_FLAG (1<<5) #define VSYNC_PIPEA_FLAG (1<<7) @@ -301,27 +303,174 @@ static void i915_vblank_tasklet(struct drm_device *dev) } } +static struct drm_device *hotplug_dev; +static int hotplug_cmd = 0; +static spinlock_t hotplug_lock = SPIN_LOCK_UNLOCKED; + +static void i915_hotplug_crt(struct drm_device *dev) +{ + struct drm_output *output; + struct intel_output *iout; + + mutex_lock(&dev->mode_config.mutex); + + /* find the crt output */ + list_for_each_entry(output, &dev->mode_config.output_list, head) { + iout = output->driver_private; + if (iout->type == INTEL_OUTPUT_ANALOG) + break; + else + iout = 0; + } + + if (iout == 0) + goto unlock; + + drm_hotplug_stage_two(dev, output); + +unlock: + mutex_unlock(&dev->mode_config.mutex); +} + +static void i915_hotplug_sdvo(struct drm_device *dev, int sdvoB) +{ + struct drm_output *output = 0; + enum drm_output_status status; + + mutex_lock(&dev->mode_config.mutex); + + output = intel_sdvo_find(dev, sdvoB); + + if (!output) { + DRM_ERROR("could not find sdvo%s output\n", sdvoB ? "B" : "C"); + goto unlock; + } + + status = output->funcs->detect(output); + + if (status != output_status_connected) + DRM_DEBUG("disconnect or unkown we don't do anything then\n"); + else + drm_hotplug_stage_two(dev, output); + + /* wierd hw bug, sdvo stop sending interupts */ + intel_sdvo_set_hotplug(output, 1); + +unlock: + mutex_unlock(&dev->mode_config.mutex); +} + +static void i915_hotplug_work_func(struct work_struct *work) +{ + struct drm_device *dev = hotplug_dev; + int crt; + int sdvoB; + int sdvoC; + + spin_lock(&hotplug_lock); + crt = hotplug_cmd & 1; + sdvoB = hotplug_cmd & 4; + sdvoC = hotplug_cmd & 8; + hotplug_cmd = 0; + spin_unlock(&hotplug_lock); + + if (crt) + i915_hotplug_crt(dev); + + if (sdvoB) + i915_hotplug_sdvo(dev, 1); + + if (sdvoC) + i915_hotplug_sdvo(dev, 0); + +} + +static int i915_run_hotplug_tasklet(struct drm_device *dev, uint32_t stat) +{ + static DECLARE_WORK(hotplug, i915_hotplug_work_func); + struct drm_i915_private *dev_priv = dev->dev_private; + + hotplug_dev = dev; + + if (stat & (1 << 11)) { + DRM_DEBUG("CRT event\n"); + + if (stat & (1 << 9) && stat & (1 << 8)) { + spin_lock(&hotplug_lock); + hotplug_cmd |= 1; + spin_unlock(&hotplug_lock); + } else { + /* handle crt disconnects */ + } + } + + if (stat & (1 << 6)) { + DRM_DEBUG("sDVOB event\n"); + + spin_lock(&hotplug_lock); + hotplug_cmd |= 4; + spin_unlock(&hotplug_lock); + } + + if (stat & (1 << 7)) { + DRM_DEBUG("sDVOC event\n"); + + spin_lock(&hotplug_lock); + hotplug_cmd |= 8; + spin_unlock(&hotplug_lock); + } + + queue_work(dev_priv->wq, &hotplug); + + return 0; +} + irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) { struct drm_device *dev = (struct drm_device *) arg; struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private; - u16 temp; + u32 temp = 0; + u32 temp2; u32 pipea_stats, pipeb_stats; pipea_stats = I915_READ(I915REG_PIPEASTAT); pipeb_stats = I915_READ(I915REG_PIPEBSTAT); - temp = I915_READ16(I915REG_INT_IDENTITY_R); + /* On i8xx hw the IIR and IER are 16bit on i9xx its 32bit */ + if (IS_I9XX(dev)) { + temp = I915_READ(I915REG_INT_IDENTITY_R); + } else { + temp = I915_READ16(I915REG_INT_IDENTITY_R); + } + + temp2 = temp; temp &= (dev_priv->irq_enable_reg | USER_INT_FLAG); +#if 0 + /* ugly despamification of pipeb event irq */ + if (temp & (0xFFFFFFF ^ ((1 << 5) | (1 << 7)))) { + DRM_DEBUG("IIR %08x\n", temp2); + DRM_DEBUG("MSK %08x\n", dev_priv->irq_enable_reg | USER_INT_FLAG); + DRM_DEBUG("M&I %08x\n", temp); + DRM_DEBUG("HOT %08x\n", I915_READ(PORT_HOTPLUG_STAT)); + } +#else #if 0 DRM_DEBUG("%s flag=%08x\n", __FUNCTION__, temp); #endif +#endif + if (temp == 0) return IRQ_NONE; - I915_WRITE16(I915REG_INT_IDENTITY_R, temp); - (void) I915_READ16(I915REG_INT_IDENTITY_R); + if (IS_I9XX(dev)) { + I915_WRITE(I915REG_INT_IDENTITY_R, temp); + (void) I915_READ(I915REG_INT_IDENTITY_R); + } else { + I915_WRITE16(I915REG_INT_IDENTITY_R, temp); + (void) I915_READ16(I915REG_INT_IDENTITY_R); + } + DRM_READMEMORYBARRIER(); dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); @@ -362,6 +511,17 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) I915_VBLANK_CLEAR); } + /* for now lest just ack it */ + if (temp & (1 << 17)) { + DRM_DEBUG("Hotplug event recived\n"); + + temp2 = I915_READ(PORT_HOTPLUG_STAT); + + i915_run_hotplug_tasklet(dev, temp2); + + I915_WRITE(PORT_HOTPLUG_STAT,temp2); + } + return IRQ_HANDLED; } @@ -536,6 +696,7 @@ int i915_irq_wait(struct drm_device *dev, void *data, void i915_enable_interrupt (struct drm_device *dev) { struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private; + struct drm_output *o; dev_priv->irq_enable_reg = USER_INT_FLAG; @@ -544,7 +705,41 @@ void i915_enable_interrupt (struct drm_device *dev) if (dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_B) dev_priv->irq_enable_reg |= VSYNC_PIPEB_FLAG; - I915_WRITE16(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg); + if (IS_I9XX(dev) && dev->mode_config.funcs) { + dev_priv->irq_enable_reg |= (1 << 17); + + /* Activate the CRT */ + I915_WRITE(PORT_HOTPLUG_EN, (1 << 9)); + + /* SDVOB */ + o = intel_sdvo_find(dev, 1); + if (o && intel_sdvo_supports_hotplug(o)) { + intel_sdvo_set_hotplug(o, 1); + I915_WRITE(PORT_HOTPLUG_EN, (1 << 26)); + } + + /* SDVOC */ + o = intel_sdvo_find(dev, 0); + if (o && intel_sdvo_supports_hotplug(o)) { + intel_sdvo_set_hotplug(o, 1); + I915_WRITE(PORT_HOTPLUG_EN, (1 << 25)); + } + + } + + if (IS_I9XX(dev)) { + I915_WRITE(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg); + } else { + I915_WRITE16(I915REG_INT_ENABLE_R, dev_priv->irq_enable_reg); + } + + DRM_DEBUG("HEN %08x\n",I915_READ(PORT_HOTPLUG_EN)); + DRM_DEBUG("HST %08x\n",I915_READ(PORT_HOTPLUG_STAT)); + DRM_DEBUG("IER %08x\n",I915_READ(I915REG_INT_ENABLE_R)); + DRM_DEBUG("SDB %08x\n",I915_READ(SDVOB)); + + I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT)); + dev_priv->irq_enabled = 1; } @@ -749,8 +944,14 @@ void i915_driver_irq_preinstall(struct drm_device * dev) struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private; I915_WRITE16(I915REG_HWSTAM, 0xeffe); - I915_WRITE16(I915REG_INT_MASK_R, 0x0); - I915_WRITE16(I915REG_INT_ENABLE_R, 0x0); + if (IS_I9XX(dev)) { + I915_WRITE(I915REG_INT_MASK_R, 0x0); + I915_WRITE(I915REG_INT_ENABLE_R, 0x0); + } else { + I915_WRITE16(I915REG_INT_MASK_R, 0x0); + I915_WRITE16(I915REG_INT_ENABLE_R, 0x0); + } + } void i915_driver_irq_postinstall(struct drm_device * dev) @@ -777,16 +978,27 @@ void i915_driver_irq_postinstall(struct drm_device * dev) void i915_driver_irq_uninstall(struct drm_device * dev) { struct drm_i915_private *dev_priv = (struct drm_i915_private *) dev->dev_private; - u16 temp; + u32 temp; if (!dev_priv) return; dev_priv->irq_enabled = 0; - I915_WRITE16(I915REG_HWSTAM, 0xffff); - I915_WRITE16(I915REG_INT_MASK_R, 0xffff); - I915_WRITE16(I915REG_INT_ENABLE_R, 0x0); - temp = I915_READ16(I915REG_INT_IDENTITY_R); - I915_WRITE16(I915REG_INT_IDENTITY_R, temp); + + if(IS_I9XX(dev)) { + I915_WRITE(I915REG_HWSTAM, 0xffffffff); + I915_WRITE(I915REG_INT_MASK_R, 0xffffffff); + I915_WRITE(I915REG_INT_ENABLE_R, 0x0); + + temp = I915_READ(I915REG_INT_IDENTITY_R); + I915_WRITE(I915REG_INT_IDENTITY_R, temp); + } else { + I915_WRITE16(I915REG_HWSTAM, 0xffff); + I915_WRITE16(I915REG_INT_MASK_R, 0xffff); + I915_WRITE16(I915REG_INT_ENABLE_R, 0x0); + + temp = I915_READ16(I915REG_INT_IDENTITY_R); + I915_WRITE16(I915REG_INT_IDENTITY_R, temp); + } } -- cgit v1.2.3