mirror of
https://gitlab.freedesktop.org/mesa/drm.git
synced 2025-12-25 07:10:11 +01:00
Modesetting Hotplug
This commit is contained in:
parent
f62a300547
commit
e239882b1e
14 changed files with 453 additions and 49 deletions
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -382,6 +382,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
|
||||
|
|
@ -539,7 +540,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
|
||||
|
|
@ -936,7 +938,7 @@ clone:
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(drm_pick_crtcs);
|
||||
|
||||
/**
|
||||
* drm_initial_config - setup a sane initial output configuration
|
||||
|
|
@ -1122,6 +1124,54 @@ int drm_crtc_set_config(struct drm_crtc *crtc, struct drm_mode_crtc *crtc_info,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 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
|
||||
|
|
|
|||
|
|
@ -577,6 +577,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);
|
||||
|
|
|
|||
|
|
@ -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++) {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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__ */
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -60,7 +60,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 +69,12 @@ 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
|
||||
bval = I915_READ(SDVOB);
|
||||
bval = bval | (1 << 26);
|
||||
} else {
|
||||
bval = I915_READ(SDVOB) | (1 << 26);
|
||||
}
|
||||
/*
|
||||
* Write the registers twice for luck. Sometimes,
|
||||
* writing them only once doesn't appear to 'stick'.
|
||||
|
|
@ -879,6 +881,72 @@ 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)
|
||||
{
|
||||
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) {
|
||||
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 {
|
||||
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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue