From 34dcf1b8f4650ed9c11d3108c0efd9ec7cca6bb6 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Fri, 5 Oct 2007 16:43:04 +0200 Subject: [PATCH] initial hotplug work --- linux-core/drm_bo.c | 1 - linux-core/drm_compat.c | 2 +- linux-core/drm_crtc.c | 8 +- linux-core/drm_drv.c | 9 ++- linux-core/i915_drv.c | 2 - linux-core/intel_crt.c | 10 +++ linux-core/intel_fb.c | 8 +- shared-core/i915_drv.h | 2 + shared-core/i915_init.c | 36 ++++----- shared-core/i915_irq.c | 174 +++++++++++++++++++++++++++++++++++++--- 10 files changed, 203 insertions(+), 49 deletions(-) diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index ea93ed16..ac06aa35 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -530,7 +530,6 @@ void drm_bo_usage_deref_unlocked(struct drm_buffer_object ** bo) } } EXPORT_SYMBOL(drm_bo_usage_deref_unlocked); - /* * Note. The caller has to register (if applicable) * and deregister fence object usage. diff --git a/linux-core/drm_compat.c b/linux-core/drm_compat.c index e51aedb7..2e7834d2 100644 --- a/linux-core/drm_compat.c +++ b/linux-core/drm_compat.c @@ -197,7 +197,7 @@ static int vm_insert_pfn(struct vm_area_struct *vma, unsigned long addr, } -static struct page *drm_bo_vm_fault(struct vm_area_struct *vma, +static struct page *drm_bo_vm_fault(struct vm_area_struct *vma, struct fault_data *data) { unsigned long address = data->address; diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index fcddc7d9..e8ca635d 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -349,6 +349,7 @@ void drm_crtc_probe_output_modes(struct drm_device *dev, int maxX, int maxY) } } } +EXPORT_SYMBOL(drm_crtc_probe_output_modes); /** * drm_crtc_set_mode - set a mode @@ -506,7 +507,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 @@ -863,7 +865,7 @@ clone: } } } - +EXPORT_SYMBOL(drm_pick_crtcs); /** * drm_initial_config - setup a sane initial output configuration @@ -1168,7 +1170,7 @@ int drm_mode_getresources(struct drm_device *dev, if (card_res->count_modes == 0) { DRM_DEBUG("probing modes %dx%d\n", dev->mode_config.max_width, dev->mode_config.max_height); - drm_crtc_probe_output_modes(dev, dev->mode_config.max_width, dev->mode_config.max_height); + /* drm_crtc_probe_output_modes(dev, dev->mode_config.max_width, dev->mode_config.max_height); */ mode_count = 0; list_for_each_entry(output, &dev->mode_config.output_list, head) { list_for_each(lh, &output->modes) diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index a313c26c..69b9f8e5 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -184,6 +184,7 @@ int drm_lastclose(struct drm_device * dev) DRM_DEBUG("\n"); +/* return 0; */ /* * We can't do much about this function failing. */ @@ -198,8 +199,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); @@ -253,11 +254,11 @@ int drm_lastclose(struct drm_device * dev) list_del(&vma->head); drm_ctl_free(vma, sizeof(*vma), DRM_MEM_VMAS); } - + /* list_for_each_entry_safe(r_list, list_t, &dev->maplist, head) { 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/i915_drv.c b/linux-core/i915_drv.c index 27e95d65..fabc8d83 100644 --- a/linux-core/i915_drv.c +++ b/linux-core/i915_drv.c @@ -309,8 +309,6 @@ static struct drm_driver driver = { DRIVER_IRQ_VBL2, .load = i915_driver_load, .unload = i915_driver_unload, - .lastclose = i915_driver_lastclose, - .preclose = i915_driver_preclose, .device_is_agp = i915_driver_device_is_agp, .vblank_wait = i915_driver_vblank_wait, .vblank_wait2 = i915_driver_vblank_wait2, diff --git a/linux-core/intel_crt.c b/linux-core/intel_crt.c index d2e1f95c..797c4828 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_fb.c b/linux-core/intel_fb.c index 04fd0fdd..c2f67cf8 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -489,8 +489,8 @@ 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; + 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); @@ -499,8 +499,8 @@ int intelfb_probe(struct drm_device *dev, struct drm_crtc *crtc) drm_bo_type_kernel, DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE | - DRM_BO_FLAG_MEM_TT | - DRM_BO_FLAG_MEM_VRAM, + DRM_BO_FLAG_MEM_VRAM | DRM_BO_FLAG_MEM_TT | + DRM_BO_FLAG_NO_MOVE, 0, 0, 0, &fbo); if (ret || !fbo) { diff --git a/shared-core/i915_drv.h b/shared-core/i915_drv.h index 2d2d3a20..b37c1cbb 100644 --- a/shared-core/i915_drv.h +++ b/shared-core/i915_drv.h @@ -129,6 +129,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 8e419b8a..1ddba5cc 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; @@ -254,8 +254,15 @@ 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_irq_install(dev); return 0; } @@ -264,9 +271,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); @@ -283,10 +296,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); @@ -315,20 +324,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 b280aa9d..2e385f61 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,128 @@ static void i915_vblank_tasklet(struct drm_device *dev) } } +static drm_device_t *hotplug_dev; + +static void i915_hotplug_work_func(struct work_struct *work) +{ + drm_device_t *dev = hotplug_dev; + drm_i915_private_t *dev_priv = dev->dev_private; + struct drm_output *output; + struct intel_output *iout; + int has_config = 0; + + DRM_DEBUG("starting monkey hunt\n"); + mutex_lock(&dev->struct_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; + } + + if (iout == 0) { + DRM_DEBUG("could not find monkey\n"); + goto unlock_struct; + } + + mutex_lock(&dev->mode_config.mutex); + + if (output->crtc && output->crtc->desired_mode) { + DRM_DEBUG("monkey has banana\n"); + has_config = 1; + } + + DRM_DEBUG("monkey looking for bananas\n"); + drm_crtc_probe_output_modes(dev, 2048, 2048); + + drm_pick_crtcs(dev); + + if (!output->crtc || !output->crtc->desired_mode) { + DRM_DEBUG("monkey had no parent or banana\n"); + goto unlock_mode; + } + + + mutex_unlock(&dev->struct_mutex); + + DRM_DEBUG("monkey eating banana\n"); + /* We should realy check if there is a fb using this crtc */ + if (!has_config) + dev->driver->fb_probe(dev, output->crtc); + else + if (!drm_crtc_set_mode(output->crtc, output->crtc->desired_mode, 0, 0)) + + DRM_DEBUG("throwing away unused bananas\n"); + drm_disable_unused_functions(dev); + mutex_lock(&dev->struct_mutex); + +unlock_mode: + mutex_unlock(&dev->mode_config.mutex); + +unlock_struct: + mutex_unlock(&dev->struct_mutex); + DRM_DEBUG("monkey hunt done\n"); +} + +static int i915_run_hotplug_tasklet(drm_device_t *dev) +{ + static DECLARE_WORK(hotplug, i915_hotplug_work_func); + drm_i915_private_t *dev_priv = dev->dev_private; + +// DRM_DEBUG("%p\n", dev); +// atomic_long_set(&hotplug.data,(unsigned long) dev); + hotplug_dev = dev; + + 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; + 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 +#if 1 + /* 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 DRM_DEBUG("%s flag=%08x\n", __FUNCTION__, temp); #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 +465,23 @@ 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); + + if (temp2 & (1 << 11) && temp2 & (1 << 9) && temp2 & (1 << 8)) { + DRM_DEBUG("CRT connected\n"); + i915_run_hotplug_tasklet(dev); + } + + if (temp2 & (1 << 11) && !(temp2 & ((1 << 9) | (1 << 8)))) + DRM_DEBUG("CRT disconnected\n"); + + I915_WRITE(PORT_HOTPLUG_STAT,temp2); + } + return IRQ_HANDLED; } @@ -533,8 +653,26 @@ 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 (dev_priv->mode_setting) */ { + dev_priv->irq_enable_reg |= (1 << 17); + + /* Activate the CRT hotplug detection */ + I915_WRITE(PORT_HOTPLUG_EN, (1 << 9)); + } + + /* if (IS_I9XX(dev_priv)) */ { + 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)); + dev_priv->irq_enabled = 1; + + DRM_DEBUG("enabled\n"); } /* Set the vblank monitor pipe @@ -766,15 +904,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_priv) */ { + 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); + } */ }