summaryrefslogtreecommitdiff
path: root/shared-core
diff options
context:
space:
mode:
authorJakob Bornecrantz <jakob@tungstengraphics.com>2007-12-04 15:36:36 +0100
committerJakob Bornecrantz <jakob@aurora.(none)>2007-12-18 02:21:08 +0100
commite239882b1e90cba0297118ec7dc432bea06b0bd0 (patch)
tree79516ad9a1e9ba8f5447ca9532fb3576cf6ac5ec /shared-core
parentf62a300547b1f495472f773587cd20c6c9da06aa (diff)
Modesetting Hotplug
Diffstat (limited to 'shared-core')
-rw-r--r--shared-core/i915_drv.h2
-rw-r--r--shared-core/i915_init.c40
-rw-r--r--shared-core/i915_irq.c238
3 files changed, 245 insertions, 35 deletions
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);
+ }
}