diff options
| -rw-r--r-- | linux-core/drmP.h | 2 | ||||
| -rw-r--r-- | linux-core/drm_bo.c | 1 | ||||
| -rw-r--r-- | linux-core/drm_crtc.c | 54 | ||||
| -rw-r--r-- | linux-core/drm_crtc.h | 1 | ||||
| -rw-r--r-- | linux-core/drm_drv.c | 8 | ||||
| -rw-r--r-- | linux-core/drm_mm.c | 15 | ||||
| -rw-r--r-- | linux-core/i915_drv.c | 5 | ||||
| -rw-r--r-- | linux-core/intel_crt.c | 10 | ||||
| -rw-r--r-- | linux-core/intel_drv.h | 5 | ||||
| -rw-r--r-- | linux-core/intel_fb.c | 45 | ||||
| -rw-r--r-- | linux-core/intel_sdvo.c | 87 | ||||
| -rw-r--r-- | shared-core/i915_drv.h | 2 | ||||
| -rw-r--r-- | shared-core/i915_init.c | 38 | ||||
| -rw-r--r-- | shared-core/i915_irq.c | 246 | 
14 files changed, 472 insertions, 47 deletions
diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 4a0cabc3..5e674b2a 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -669,6 +669,7 @@ struct drm_driver {  	/* FB routines, if present */  	int (*fb_probe)(struct drm_device *dev, struct drm_crtc *crtc);  	int (*fb_remove)(struct drm_device *dev, struct drm_crtc *crtc); +	int (*fb_resize)(struct drm_device *dev, struct drm_crtc *crtc);  	struct drm_fence_driver *fence_driver;  	struct drm_bo_driver *bo_driver; @@ -1210,6 +1211,7 @@ extern int drm_mm_clean(struct drm_mm *mm);  extern unsigned long drm_mm_tail_space(struct drm_mm *mm);  extern int drm_mm_remove_space_from_tail(struct drm_mm *mm, unsigned long size);  extern int drm_mm_add_space_to_tail(struct drm_mm *mm, unsigned long size); +extern void drm_mm_print(struct drm_mm *mm, const char *name);  static inline struct drm_mm *drm_get_mm(struct drm_mm_node *block)  { diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index c89d6608..e4ec24e2 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -569,7 +569,6 @@ void drm_putback_buffer_objects(struct drm_device *dev)  }  EXPORT_SYMBOL(drm_putback_buffer_objects); -  /*   * Note. The caller has to register (if applicable)   * and deregister fence object usage. diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index 405b54b7..fef2700a 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -396,6 +396,7 @@ void drm_crtc_probe_output_modes(struct drm_device *dev, int maxX, int maxY)  		drm_crtc_probe_single_output_modes(output, maxX, maxY);  	}  } +EXPORT_SYMBOL(drm_crtc_probe_output_modes);  /**   * drm_crtc_set_mode - set a mode @@ -553,7 +554,8 @@ void drm_disable_unused_functions(struct drm_device *dev)  			crtc->funcs->dpms(crtc, DPMSModeOff);  	}  } -	 +EXPORT_SYMBOL(drm_disable_unused_functions); +  /**   * drm_mode_probed_add - add a mode to the specified output's probed mode list   * @output: output the new mode @@ -920,7 +922,7 @@ clone:      		}  	}  } - +EXPORT_SYMBOL(drm_pick_crtcs);  /**   * drm_initial_config - setup a sane initial output configuration @@ -1107,6 +1109,54 @@ int drm_crtc_set_config(struct drm_crtc *crtc, struct drm_mode_crtc *crtc_info,  }  /** + * drm_hotplug_stage_two + * @dev DRM device + * @output hotpluged output + * + * LOCKING. + * Caller must hold mode config lock, function might grap struct lock. + * + * Stage two of a hotplug. + * + * RETURNS: + * Zero on success, errno on failure. + */ +int drm_hotplug_stage_two(struct drm_device *dev, struct drm_output *output) +{ +	int has_config = 0; + +	if (output->crtc && output->crtc->desired_mode) { +		DRM_DEBUG("drm thinks that the output already has a config\n"); +		has_config = 1; +	} + +	drm_crtc_probe_output_modes(dev, 2048, 2048); + +	if (!has_config) +		drm_pick_crtcs(dev); + +	if (!output->crtc || !output->crtc->desired_mode) { +		DRM_DEBUG("could not find a desired mode or crtc for output\n"); +		return 1; +	} + +	/* We should realy check if there is a fb using this crtc */ +	if (!has_config) +		dev->driver->fb_probe(dev, output->crtc); +	else { +		dev->driver->fb_resize(dev, output->crtc); + +		if (!drm_crtc_set_mode(output->crtc, output->crtc->desired_mode, 0, 0)) +			DRM_ERROR("failed to set mode after hotplug\n"); +	} + +	drm_disable_unused_functions(dev); + +	return 0; +} +EXPORT_SYMBOL(drm_hotplug_stage_two); + +/**   * drm_crtc_convert_to_umode - convert a drm_display_mode into a modeinfo   * @out: drm_mode_modeinfo struct to return to the user   * @in: drm_display_mode to use diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index d133e0e0..54e0c000 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -579,6 +579,7 @@ extern int drmfb_probe(struct drm_device *dev, struct drm_crtc *crtc);  extern int drmfb_remove(struct drm_device *dev, struct drm_framebuffer *fb);  extern bool drm_crtc_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode,  		       int x, int y); +extern int drm_hotplug_stage_two(struct drm_device *dev, struct drm_output *output);  extern int drm_output_attach_property(struct drm_output *output,  				      struct drm_property *property, uint64_t init_val); diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index 0b9ce30a..ab02c659 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -181,6 +181,7 @@ int drm_lastclose(struct drm_device * dev)  	DRM_DEBUG("\n"); +/*	return 0; */  	/*  	 * We can't do much about this function failing.  	 */ @@ -195,8 +196,8 @@ int drm_lastclose(struct drm_device * dev)  		dev->unique_len = 0;  	} -	if (dev->irq_enabled) -		drm_irq_uninstall(dev); +/*	if (dev->irq_enabled) +		drm_irq_uninstall(dev); */  	/* Free drawable information memory */  	mutex_lock(&dev->struct_mutex); @@ -251,12 +252,13 @@ int drm_lastclose(struct drm_device * dev)  		drm_ctl_free(vma, sizeof(*vma), DRM_MEM_VMAS);  	} +	/*  	list_for_each_entry_safe(r_list, list_t, &dev->maplist, head) {  		if (!(r_list->map->flags & _DRM_DRIVER)) {  			drm_rmmap_locked(dev, r_list->map);  			r_list = NULL;  		} -	} +	}*/  	if (drm_core_check_feature(dev, DRIVER_DMA_QUEUE) && dev->queuelist) {  		for (i = 0; i < dev->queue_count; i++) { diff --git a/linux-core/drm_mm.c b/linux-core/drm_mm.c index 59110293..28726a65 100644 --- a/linux-core/drm_mm.c +++ b/linux-core/drm_mm.c @@ -294,3 +294,18 @@ void drm_mm_takedown(struct drm_mm * mm)  }  EXPORT_SYMBOL(drm_mm_takedown); + +void drm_mm_print(struct drm_mm *mm, const char *name) +{ +	struct list_head *list; +	const struct list_head *mm_stack = &mm->ml_entry; +	struct drm_mm_node *entry; + +	DRM_DEBUG("Memory usage for '%s'\n", name ? name : "unknown"); +	list_for_each(list, mm_stack) { +		entry = list_entry(list, struct drm_mm_node, ml_entry); +		DRM_DEBUG("\t0x%08lx %li %s pages\n", entry->start, entry->size, +			entry->free ? "free" : "used"); +	} +} +EXPORT_SYMBOL(drm_mm_print); diff --git a/linux-core/i915_drv.c b/linux-core/i915_drv.c index fb4149c4..598039dc 100644 --- a/linux-core/i915_drv.c +++ b/linux-core/i915_drv.c @@ -541,8 +541,8 @@ static struct drm_driver driver = {  	    DRIVER_IRQ_VBL2,  	.load = i915_driver_load,  	.unload = i915_driver_unload, -	.lastclose = i915_driver_lastclose, -	.preclose = i915_driver_preclose, +/*	.lastclose = i915_driver_lastclose, +	.preclose = i915_driver_preclose, */  	.suspend = i915_suspend,  	.resume = i915_resume,  	.device_is_agp = i915_driver_device_is_agp, @@ -557,6 +557,7 @@ static struct drm_driver driver = {  	.get_reg_ofs = drm_core_get_reg_ofs,  	.fb_probe = intelfb_probe,  	.fb_remove = intelfb_remove, +	.fb_resize = intelfb_resize,  	.ioctls = i915_ioctls,  	.fops = {  		.owner = THIS_MODULE, diff --git a/linux-core/intel_crt.c b/linux-core/intel_crt.c index 74e3dcd6..4be71cba 100644 --- a/linux-core/intel_crt.c +++ b/linux-core/intel_crt.c @@ -142,6 +142,7 @@ static bool intel_crt_detect_hotplug(struct drm_output *output)  	struct drm_device *dev = output->dev;  	struct drm_i915_private *dev_priv = dev->dev_private;  	u32 temp; +#if 1  	unsigned long timeout = jiffies + msecs_to_jiffies(1000);  	temp = I915_READ(PORT_HOTPLUG_EN); @@ -160,6 +161,15 @@ static bool intel_crt_detect_hotplug(struct drm_output *output)  		return true;  	return false; +#else +	temp = I915_READ(PORT_HOTPLUG_STAT); +	DRM_DEBUG("HST 0x%08x\n", temp); + +	if (temp & (1 << 8) && temp & (1 << 9)) +		return true; + +	return false; +#endif  }  static bool intel_crt_detect_ddc(struct drm_output *output) diff --git a/linux-core/intel_drv.h b/linux-core/intel_drv.h index 7de4b924..06335b18 100644 --- a/linux-core/intel_drv.h +++ b/linux-core/intel_drv.h @@ -76,7 +76,12 @@ extern struct drm_display_mode *intel_crtc_mode_get(struct drm_device *dev,  extern void intel_wait_for_vblank(struct drm_device *dev);  extern struct drm_crtc *intel_get_crtc_from_pipe(struct drm_device *dev, int pipe); +extern struct drm_output* intel_sdvo_find(struct drm_device *dev, int sdvoB); +extern int intel_sdvo_supports_hotplug(struct drm_output *output); +extern void intel_sdvo_set_hotplug(struct drm_output *output, int enable); +  extern int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc);  extern int intelfb_remove(struct drm_device *dev, struct drm_crtc *crtc); +extern int intelfb_resize(struct drm_device *dev, struct drm_crtc *crtc);  #endif /* __INTEL_DRV_H__ */ diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index 32c7dc31..b67c0fcc 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -489,6 +489,46 @@ static struct fb_ops intelfb_ops = {  	.fb_imageblit = cfb_imageblit, //intelfb_imageblit,  }; +/** + * Curretly it is assumed that the old framebuffer is reused. + * + * LOCKING + * caller should hold the mode config lock. + * + */ +int intelfb_resize(struct drm_device *dev, struct drm_crtc *crtc) +{ +    struct fb_info *info; +	struct drm_framebuffer *fb; +	struct drm_display_mode *mode = crtc->desired_mode; + +	fb = crtc->fb; +	if (!fb) +		return 1; + +	info = fb->fbdev; +	if (!info) +		return 1; + +	if (!mode) +		return 1; + +	info->var.xres = mode->hdisplay; +	info->var.right_margin = mode->hsync_start - mode->hdisplay; +	info->var.hsync_len = mode->hsync_end - mode->hsync_start; +	info->var.left_margin = mode->htotal - mode->hsync_end; +	info->var.yres = mode->vdisplay; +	info->var.lower_margin = mode->vsync_start - mode->vdisplay; +	info->var.vsync_len = mode->vsync_end - mode->vsync_start; +	info->var.upper_margin = mode->vtotal - mode->vsync_end; +	info->var.pixclock = 10000000 / mode->htotal * 1000 / mode->vtotal * 100; +    /* avoid overflow */ +	info->var.pixclock = info->var.pixclock * 1000 / mode->vrefresh; + +	return 0; +} +EXPORT_SYMBOL(intelfb_resize); +  int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc)  {  	struct fb_info *info; @@ -512,8 +552,9 @@ int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc)  	}  	crtc->fb = fb; -	fb->width = crtc->desired_mode->hdisplay; -	fb->height = crtc->desired_mode->vdisplay; +	/* To allow resizeing without swapping buffers */ +	fb->width = 2048;/* crtc->desired_mode->hdisplay; */ +	fb->height = 2048;/* crtc->desired_mode->vdisplay; */  	fb->bits_per_pixel = 32;  	fb->pitch = fb->width * ((fb->bits_per_pixel + 1) / 8); diff --git a/linux-core/intel_sdvo.c b/linux-core/intel_sdvo.c index 7f55829b..3887df00 100644 --- a/linux-core/intel_sdvo.c +++ b/linux-core/intel_sdvo.c @@ -53,6 +53,7 @@ struct intel_sdvo_priv {  	struct intel_sdvo_dtd save_input_dtd_1, save_input_dtd_2;  	struct intel_sdvo_dtd save_output_dtd[16];  	u32 save_SDVOX; +	int hotplug_enabled;  };  /** @@ -60,7 +61,7 @@ struct intel_sdvo_priv {   * SDVOB and SDVOC to work around apparent hardware issues (according to   * comments in the BIOS).   */ -static void intel_sdvo_write_sdvox(struct drm_output *output, u32 val) +void intel_sdvo_write_sdvox(struct drm_output *output, u32 val)  {  	struct drm_device *dev = output->dev;  	struct drm_i915_private *dev_priv = dev->dev_private; @@ -69,10 +70,17 @@ static void intel_sdvo_write_sdvox(struct drm_output *output, u32 val)  	u32 bval = val, cval = val;  	int i; -	if (sdvo_priv->output_device == SDVOB) +	if (sdvo_priv->output_device == SDVOB) {  		cval = I915_READ(SDVOC); -	else + +		if (sdvo_priv->hotplug_enabled) +			bval = bval | (1 << 26); +	} else {  		bval = I915_READ(SDVOB); + +		if (sdvo_priv->hotplug_enabled) +			cval = cval | (1 << 26); +	}  	/*  	 * Write the registers twice for luck. Sometimes,  	 * writing them only once doesn't appear to 'stick'. @@ -879,6 +887,78 @@ void intel_sdvo_dump(void)  } +struct drm_output* intel_sdvo_find(struct drm_device *dev, int sdvoB) +{ +	struct drm_output *output = 0; +	struct intel_output *iout = 0; +	struct intel_sdvo_priv *sdvo; + +	/* find the sdvo output */ +	list_for_each_entry(output, &dev->mode_config.output_list, head) { +		iout = output->driver_private; + +		if (iout->type != INTEL_OUTPUT_SDVO) +			continue; + +		sdvo = iout->dev_priv; + +		if (sdvo->output_device == SDVOB && sdvoB) +			return output; + +		if (sdvo->output_device == SDVOC && !sdvoB) +			return output; + +    } + +	return 0; +} + +int intel_sdvo_supports_hotplug(struct drm_output *output) +{ +	u8 response[2]; +	u8 status; +	DRM_DEBUG("\n"); + +	if (!output) +		return 0; + +	intel_sdvo_write_cmd(output, SDVO_CMD_GET_HOT_PLUG_SUPPORT, NULL, 0); +	status = intel_sdvo_read_response(output, &response, 2); + +	if (response[0] !=0) +		return 1; + +	return 0; +} + +void intel_sdvo_set_hotplug(struct drm_output *output, int on) +{ +	struct intel_output *intel_output = output->driver_private; +	struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv; +	u8 response[2]; +	u8 status; + +	intel_sdvo_write_cmd(output, SDVO_CMD_GET_ACTIVE_HOT_PLUG, NULL, 0); +	intel_sdvo_read_response(output, &response, 2); + +	if (on) { +		sdvo_priv->hotplug_enabled = 1; + +		intel_sdvo_write_cmd(output, SDVO_CMD_GET_HOT_PLUG_SUPPORT, NULL, 0); +		status = intel_sdvo_read_response(output, &response, 2); + +		intel_sdvo_write_cmd(output, SDVO_CMD_SET_ACTIVE_HOT_PLUG, &response, 2); +	} else { +		sdvo_priv->hotplug_enabled = 0; + +		response[0] = 0; +		response[1] = 0; +		intel_sdvo_write_cmd(output, SDVO_CMD_SET_ACTIVE_HOT_PLUG, &response, 2); +	} + +	intel_sdvo_write_cmd(output, SDVO_CMD_GET_ACTIVE_HOT_PLUG, NULL, 0); +	intel_sdvo_read_response(output, &response, 2); +}  static enum drm_output_status intel_sdvo_detect(struct drm_output *output)  { @@ -994,6 +1074,7 @@ void intel_sdvo_init(struct drm_device *dev, int output_device)  	}  	sdvo_priv->output_device = output_device; +	sdvo_priv->hotplug_enabled = 0;  	intel_output->i2c_bus = i2cbus;  	intel_output->dev_priv = sdvo_priv; 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 e44cb930..3b271b17 100644 --- a/shared-core/i915_init.c +++ b/shared-core/i915_init.c @@ -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..ac5361f2 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -31,9 +31,12 @@  #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) +#define HOTPLUG_FLAG (1 << 17)  #define MAX_NOPID ((u32)~0) @@ -301,27 +304,181 @@ static void i915_vblank_tasklet(struct drm_device *dev)  	}  } +#define HOTPLUG_CMD_CRT 1 +#define HOTPLUG_CMD_SDVOB 4 +#define HOTPLUG_CMD_SDVOC 8 + +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); +} +/* + * This code is called in a more safe envirmoent to handle the hotplugs. + * Add code here for hotplug love to userspace. + */ +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 & HOTPLUG_CMD_CRT; +	sdvoB = hotplug_cmd & HOTPLUG_CMD_SDVOB; +	sdvoC = hotplug_cmd & HOTPLUG_CMD_SDVOC; +	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 & CRT_HOTPLUG_INT_STATUS) { +		DRM_DEBUG("CRT event\n"); + +		if (stat & CRT_HOTPLUG_MONITOR_MASK) { +			spin_lock(&hotplug_lock); +			hotplug_cmd |= HOTPLUG_CMD_CRT; +			spin_unlock(&hotplug_lock); +		} else { +			/* handle crt disconnects */ +		} +	} + +	if (stat & SDVOB_HOTPLUG_INT_STATUS) { +		DRM_DEBUG("sDVOB event\n"); + +		spin_lock(&hotplug_lock); +		hotplug_cmd |= HOTPLUG_CMD_SDVOB; +		spin_unlock(&hotplug_lock); +	} + +	if (stat & SDVOC_HOTPLUG_INT_STATUS) { +		DRM_DEBUG("sDVOC event\n"); + +		spin_lock(&hotplug_lock); +		hotplug_cmd |= HOTPLUG_CMD_SDVOC; +		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 +519,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 received\n"); + +		temp2 = I915_READ(PORT_HOTPLUG_STAT); + +		i915_run_hotplug_tasklet(dev, temp2); + +		I915_WRITE(PORT_HOTPLUG_STAT,temp2); +	} +  	return IRQ_HANDLED;  } @@ -536,6 +704,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 +713,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.num_output) { +		dev_priv->irq_enable_reg |= HOTPLUG_FLAG; + +		/* Activate the CRT */ +		I915_WRITE(PORT_HOTPLUG_EN, CRT_HOTPLUG_INT_EN); + +		/* 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, SDVOB_HOTPLUG_INT_EN); +		} + +		/* 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, SDVOC_HOTPLUG_INT_EN); +		} + +	} + +	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 +952,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 +986,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); +	}  }  | 
