2
0
mirror of https://github.com/edk2-porting/linux-next.git synced 2024-12-24 05:04:00 +08:00

Merge branch 'drm-intel-next' of git://git.kernel.org/pub/scm/linux/kernel/git/anholt/drm-intel

* 'drm-intel-next' of git://git.kernel.org/pub/scm/linux/kernel/git/anholt/drm-intel: (22 commits)
  drm/i915: Fix for LVDS VBT change on IGDNG
  drm/i915: Zap the GTT mapping when transitioning from untiled to tiled.
  drm/i915: Refactor calls to unmap_mapping_range
  drm/i915: Avoid saving/restore the modesetting registers twice in KMS mode
  drm: Disable the unused connectors explicitly when resuming with KMS.
  drm/i915: Restore the KMS modeset for every activated CRTC
  drm/i915: Fix harmless warning from patch merged after i2c rework.
  drm/i915: Disable GEM when a broken video BIOS takes up the whole aperture.
  drm/i915: Check the LID device to decide whether the LVDS should be initialized
  drm/i915: Move lock to more reasonable location
  drm/i915: Add gtt_offset to gem object list debugfs output
  drm/i915: Remove gtt_bound from drm_i915_gem_object
  drm/i915: Disable VGA output when doing DRM_MODE_DPMS_OFF.
  drm/i915: crt fetch EDID by DVI-I converter on G4x platform
  drm/i915: Don't update display FIFO watermark on IGDNG
  drm/i915: Adjust DisplayPort clocks to use 96MHz reference
  drm/i915: Make driver less chatty
  drm/i915: fix up a raw 64bit divide
  drm/i915: enable sdvo lvds scaling function.
  drm/i915: Set SSC frequency for 8xx chips correctly
  ...
This commit is contained in:
Linus Torvalds 2009-07-10 19:10:59 -07:00
commit bb8ad2815a
19 changed files with 1159 additions and 188 deletions

View File

@ -1090,6 +1090,8 @@ int drm_helper_resume_force_mode(struct drm_device *dev)
if (ret == false) if (ret == false)
DRM_ERROR("failed to set mode on crtc %p\n", crtc); DRM_ERROR("failed to set mode on crtc %p\n", crtc);
} }
/* disable the unused connectors while restoring the modesetting */
drm_helper_disable_unused_functions(dev);
return 0; return 0;
} }
EXPORT_SYMBOL(drm_helper_resume_force_mode); EXPORT_SYMBOL(drm_helper_resume_force_mode);

View File

@ -846,7 +846,7 @@ static int i915_set_status_page(struct drm_device *dev, void *data,
return 0; return 0;
} }
printk(KERN_DEBUG "set status page addr 0x%08x\n", (u32)hws->addr); DRM_DEBUG("set status page addr 0x%08x\n", (u32)hws->addr);
dev_priv->status_gfx_addr = hws->addr & (0x1ffff<<12); dev_priv->status_gfx_addr = hws->addr & (0x1ffff<<12);
@ -885,8 +885,8 @@ static int i915_set_status_page(struct drm_device *dev, void *data,
* some RAM for the framebuffer at early boot. This code figures out * some RAM for the framebuffer at early boot. This code figures out
* how much was set aside so we can use it for our own purposes. * how much was set aside so we can use it for our own purposes.
*/ */
static int i915_probe_agp(struct drm_device *dev, unsigned long *aperture_size, static int i915_probe_agp(struct drm_device *dev, uint32_t *aperture_size,
unsigned long *preallocated_size) uint32_t *preallocated_size)
{ {
struct pci_dev *bridge_dev; struct pci_dev *bridge_dev;
u16 tmp = 0; u16 tmp = 0;
@ -984,10 +984,11 @@ static int i915_probe_agp(struct drm_device *dev, unsigned long *aperture_size,
return 0; return 0;
} }
static int i915_load_modeset_init(struct drm_device *dev) static int i915_load_modeset_init(struct drm_device *dev,
unsigned long prealloc_size,
unsigned long agp_size)
{ {
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
unsigned long agp_size, prealloc_size;
int fb_bar = IS_I9XX(dev) ? 2 : 0; int fb_bar = IS_I9XX(dev) ? 2 : 0;
int ret = 0; int ret = 0;
@ -1002,10 +1003,6 @@ static int i915_load_modeset_init(struct drm_device *dev)
if (IS_I965G(dev) || IS_G33(dev)) if (IS_I965G(dev) || IS_G33(dev))
dev_priv->cursor_needs_physical = false; dev_priv->cursor_needs_physical = false;
ret = i915_probe_agp(dev, &agp_size, &prealloc_size);
if (ret)
goto out;
/* Basic memrange allocator for stolen space (aka vram) */ /* Basic memrange allocator for stolen space (aka vram) */
drm_mm_init(&dev_priv->vram, 0, prealloc_size); drm_mm_init(&dev_priv->vram, 0, prealloc_size);
@ -1082,6 +1079,44 @@ void i915_master_destroy(struct drm_device *dev, struct drm_master *master)
master->driver_priv = NULL; master->driver_priv = NULL;
} }
static void i915_get_mem_freq(struct drm_device *dev)
{
drm_i915_private_t *dev_priv = dev->dev_private;
u32 tmp;
if (!IS_IGD(dev))
return;
tmp = I915_READ(CLKCFG);
switch (tmp & CLKCFG_FSB_MASK) {
case CLKCFG_FSB_533:
dev_priv->fsb_freq = 533; /* 133*4 */
break;
case CLKCFG_FSB_800:
dev_priv->fsb_freq = 800; /* 200*4 */
break;
case CLKCFG_FSB_667:
dev_priv->fsb_freq = 667; /* 167*4 */
break;
case CLKCFG_FSB_400:
dev_priv->fsb_freq = 400; /* 100*4 */
break;
}
switch (tmp & CLKCFG_MEM_MASK) {
case CLKCFG_MEM_533:
dev_priv->mem_freq = 533;
break;
case CLKCFG_MEM_667:
dev_priv->mem_freq = 667;
break;
case CLKCFG_MEM_800:
dev_priv->mem_freq = 800;
break;
}
}
/** /**
* i915_driver_load - setup chip and create an initial config * i915_driver_load - setup chip and create an initial config
* @dev: DRM device * @dev: DRM device
@ -1098,6 +1133,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
resource_size_t base, size; resource_size_t base, size;
int ret = 0, mmio_bar = IS_I9XX(dev) ? 0 : 1; int ret = 0, mmio_bar = IS_I9XX(dev) ? 0 : 1;
uint32_t agp_size, prealloc_size;
/* i915 has 4 more counters */ /* i915 has 4 more counters */
dev->counters += 4; dev->counters += 4;
@ -1146,9 +1182,22 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
"performance may suffer.\n"); "performance may suffer.\n");
} }
ret = i915_probe_agp(dev, &agp_size, &prealloc_size);
if (ret)
goto out_iomapfree;
/* enable GEM by default */ /* enable GEM by default */
dev_priv->has_gem = 1; dev_priv->has_gem = 1;
if (prealloc_size > agp_size * 3 / 4) {
DRM_ERROR("Detected broken video BIOS with %d/%dkB of video "
"memory stolen.\n",
prealloc_size / 1024, agp_size / 1024);
DRM_ERROR("Disabling GEM. (try reducing stolen memory or "
"updating the BIOS to fix).\n");
dev_priv->has_gem = 0;
}
dev->driver->get_vblank_counter = i915_get_vblank_counter; dev->driver->get_vblank_counter = i915_get_vblank_counter;
dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */ dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */
if (IS_G4X(dev) || IS_IGDNG(dev)) { if (IS_G4X(dev) || IS_IGDNG(dev)) {
@ -1165,6 +1214,8 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
goto out_iomapfree; goto out_iomapfree;
} }
i915_get_mem_freq(dev);
/* On the 945G/GM, the chipset reports the MSI capability on the /* On the 945G/GM, the chipset reports the MSI capability on the
* integrated graphics even though the support isn't actually there * integrated graphics even though the support isn't actually there
* according to the published specs. It doesn't appear to function * according to the published specs. It doesn't appear to function
@ -1180,6 +1231,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
pci_enable_msi(dev->pdev); pci_enable_msi(dev->pdev);
spin_lock_init(&dev_priv->user_irq_lock); spin_lock_init(&dev_priv->user_irq_lock);
spin_lock_init(&dev_priv->error_lock);
dev_priv->user_irq_refcount = 0; dev_priv->user_irq_refcount = 0;
ret = drm_vblank_init(dev, I915_NUM_PIPE); ret = drm_vblank_init(dev, I915_NUM_PIPE);
@ -1190,7 +1242,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
} }
if (drm_core_check_feature(dev, DRIVER_MODESET)) { if (drm_core_check_feature(dev, DRIVER_MODESET)) {
ret = i915_load_modeset_init(dev); ret = i915_load_modeset_init(dev, prealloc_size, agp_size);
if (ret < 0) { if (ret < 0) {
DRM_ERROR("failed to init modeset\n"); DRM_ERROR("failed to init modeset\n");
goto out_rmmap; goto out_rmmap;

View File

@ -35,6 +35,7 @@
#include "drm_pciids.h" #include "drm_pciids.h"
#include <linux/console.h> #include <linux/console.h>
#include "drm_crtc_helper.h"
static unsigned int i915_modeset = -1; static unsigned int i915_modeset = -1;
module_param_named(modeset, i915_modeset, int, 0400); module_param_named(modeset, i915_modeset, int, 0400);
@ -57,8 +58,8 @@ static int i915_suspend(struct drm_device *dev, pm_message_t state)
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
if (!dev || !dev_priv) { if (!dev || !dev_priv) {
printk(KERN_ERR "dev: %p, dev_priv: %p\n", dev, dev_priv); DRM_ERROR("dev: %p, dev_priv: %p\n", dev, dev_priv);
printk(KERN_ERR "DRM not initialized, aborting suspend.\n"); DRM_ERROR("DRM not initialized, aborting suspend.\n");
return -ENODEV; return -ENODEV;
} }
@ -115,6 +116,10 @@ static int i915_resume(struct drm_device *dev)
drm_irq_install(dev); drm_irq_install(dev);
} }
if (drm_core_check_feature(dev, DRIVER_MODESET)) {
/* Resume the modeset for every activated CRTC */
drm_helper_resume_force_mode(dev);
}
return ret; return ret;
} }

View File

@ -133,6 +133,22 @@ struct sdvo_device_mapping {
u8 initialized; u8 initialized;
}; };
struct drm_i915_error_state {
u32 eir;
u32 pgtbl_er;
u32 pipeastat;
u32 pipebstat;
u32 ipeir;
u32 ipehr;
u32 instdone;
u32 acthd;
u32 instpm;
u32 instps;
u32 instdone1;
u32 seqno;
struct timeval time;
};
typedef struct drm_i915_private { typedef struct drm_i915_private {
struct drm_device *dev; struct drm_device *dev;
@ -209,6 +225,11 @@ typedef struct drm_i915_private {
int fence_reg_start; /* 4 if userland hasn't ioctl'd us yet */ int fence_reg_start; /* 4 if userland hasn't ioctl'd us yet */
int num_fence_regs; /* 8 on pre-965, 16 otherwise */ int num_fence_regs; /* 8 on pre-965, 16 otherwise */
unsigned int fsb_freq, mem_freq;
spinlock_t error_lock;
struct drm_i915_error_state *first_error;
/* Register state */ /* Register state */
u8 saveLBB; u8 saveLBB;
u32 saveDSPACNTR; u32 saveDSPACNTR;
@ -468,9 +489,6 @@ struct drm_i915_gem_object {
*/ */
int fence_reg; int fence_reg;
/** Boolean whether this object has a valid gtt offset. */
int gtt_bound;
/** How many users have pinned this object in GTT space */ /** How many users have pinned this object in GTT space */
int pin_count; int pin_count;
@ -655,6 +673,7 @@ void i915_gem_free_object(struct drm_gem_object *obj);
int i915_gem_object_pin(struct drm_gem_object *obj, uint32_t alignment); int i915_gem_object_pin(struct drm_gem_object *obj, uint32_t alignment);
void i915_gem_object_unpin(struct drm_gem_object *obj); void i915_gem_object_unpin(struct drm_gem_object *obj);
int i915_gem_object_unbind(struct drm_gem_object *obj); int i915_gem_object_unbind(struct drm_gem_object *obj);
void i915_gem_release_mmap(struct drm_gem_object *obj);
void i915_gem_lastclose(struct drm_device *dev); void i915_gem_lastclose(struct drm_device *dev);
uint32_t i915_get_gem_seqno(struct drm_device *dev); uint32_t i915_get_gem_seqno(struct drm_device *dev);
int i915_gem_object_get_fence_reg(struct drm_gem_object *obj); int i915_gem_object_get_fence_reg(struct drm_gem_object *obj);
@ -870,6 +889,8 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller);
#define SUPPORTS_INTEGRATED_HDMI(dev) (IS_G4X(dev) || IS_IGDNG(dev)) #define SUPPORTS_INTEGRATED_HDMI(dev) (IS_G4X(dev) || IS_IGDNG(dev))
#define SUPPORTS_INTEGRATED_DP(dev) (IS_G4X(dev) || IS_IGDNG(dev)) #define SUPPORTS_INTEGRATED_DP(dev) (IS_G4X(dev) || IS_IGDNG(dev))
#define I915_HAS_HOTPLUG(dev) (IS_I945G(dev) || IS_I945GM(dev) || IS_I965G(dev)) #define I915_HAS_HOTPLUG(dev) (IS_I945G(dev) || IS_I945GM(dev) || IS_I965G(dev))
/* dsparb controlled by hw only */
#define DSPARB_HWCONTROL(dev) (IS_G4X(dev) || IS_IGDNG(dev))
#define PRIMARY_RINGBUFFER_SIZE (128*1024) #define PRIMARY_RINGBUFFER_SIZE (128*1024)

View File

@ -1252,6 +1252,31 @@ out_free_list:
return ret; return ret;
} }
/**
* i915_gem_release_mmap - remove physical page mappings
* @obj: obj in question
*
* Preserve the reservation of the mmaping with the DRM core code, but
* relinquish ownership of the pages back to the system.
*
* It is vital that we remove the page mapping if we have mapped a tiled
* object through the GTT and then lose the fence register due to
* resource pressure. Similarly if the object has been moved out of the
* aperture, than pages mapped into userspace must be revoked. Removing the
* mapping will then trigger a page fault on the next user access, allowing
* fixup by i915_gem_fault().
*/
void
i915_gem_release_mmap(struct drm_gem_object *obj)
{
struct drm_device *dev = obj->dev;
struct drm_i915_gem_object *obj_priv = obj->driver_private;
if (dev->dev_mapping)
unmap_mapping_range(dev->dev_mapping,
obj_priv->mmap_offset, obj->size, 1);
}
static void static void
i915_gem_free_mmap_offset(struct drm_gem_object *obj) i915_gem_free_mmap_offset(struct drm_gem_object *obj)
{ {
@ -1861,7 +1886,6 @@ i915_gem_object_unbind(struct drm_gem_object *obj)
{ {
struct drm_device *dev = obj->dev; struct drm_device *dev = obj->dev;
struct drm_i915_gem_object *obj_priv = obj->driver_private; struct drm_i915_gem_object *obj_priv = obj->driver_private;
loff_t offset;
int ret = 0; int ret = 0;
#if WATCH_BUF #if WATCH_BUF
@ -1898,9 +1922,7 @@ i915_gem_object_unbind(struct drm_gem_object *obj)
BUG_ON(obj_priv->active); BUG_ON(obj_priv->active);
/* blow away mappings if mapped through GTT */ /* blow away mappings if mapped through GTT */
offset = ((loff_t) obj->map_list.hash.key) << PAGE_SHIFT; i915_gem_release_mmap(obj);
if (dev->dev_mapping)
unmap_mapping_range(dev->dev_mapping, offset, obj->size, 1);
if (obj_priv->fence_reg != I915_FENCE_REG_NONE) if (obj_priv->fence_reg != I915_FENCE_REG_NONE)
i915_gem_clear_fence_reg(obj); i915_gem_clear_fence_reg(obj);
@ -2222,7 +2244,6 @@ try_again:
/* None available, try to steal one or wait for a user to finish */ /* None available, try to steal one or wait for a user to finish */
if (i == dev_priv->num_fence_regs) { if (i == dev_priv->num_fence_regs) {
uint32_t seqno = dev_priv->mm.next_gem_seqno; uint32_t seqno = dev_priv->mm.next_gem_seqno;
loff_t offset;
if (avail == 0) if (avail == 0)
return -ENOSPC; return -ENOSPC;
@ -2274,10 +2295,7 @@ try_again:
* Zap this virtual mapping so we can set up a fence again * Zap this virtual mapping so we can set up a fence again
* for this object next time we need it. * for this object next time we need it.
*/ */
offset = ((loff_t) reg->obj->map_list.hash.key) << PAGE_SHIFT; i915_gem_release_mmap(reg->obj);
if (dev->dev_mapping)
unmap_mapping_range(dev->dev_mapping, offset,
reg->obj->size, 1);
old_obj_priv->fence_reg = I915_FENCE_REG_NONE; old_obj_priv->fence_reg = I915_FENCE_REG_NONE;
} }

View File

@ -75,11 +75,10 @@ static int i915_gem_object_list_info(struct seq_file *m, void *data)
case ACTIVE_LIST: case ACTIVE_LIST:
seq_printf(m, "Active:\n"); seq_printf(m, "Active:\n");
lock = &dev_priv->mm.active_list_lock; lock = &dev_priv->mm.active_list_lock;
spin_lock(lock);
head = &dev_priv->mm.active_list; head = &dev_priv->mm.active_list;
break; break;
case INACTIVE_LIST: case INACTIVE_LIST:
seq_printf(m, "Inctive:\n"); seq_printf(m, "Inactive:\n");
head = &dev_priv->mm.inactive_list; head = &dev_priv->mm.inactive_list;
break; break;
case FLUSHING_LIST: case FLUSHING_LIST:
@ -91,6 +90,8 @@ static int i915_gem_object_list_info(struct seq_file *m, void *data)
return 0; return 0;
} }
if (lock)
spin_lock(lock);
list_for_each_entry(obj_priv, head, list) list_for_each_entry(obj_priv, head, list)
{ {
struct drm_gem_object *obj = obj_priv->obj; struct drm_gem_object *obj = obj_priv->obj;
@ -104,7 +105,10 @@ static int i915_gem_object_list_info(struct seq_file *m, void *data)
if (obj->name) if (obj->name)
seq_printf(m, " (name: %d)", obj->name); seq_printf(m, " (name: %d)", obj->name);
if (obj_priv->fence_reg != I915_FENCE_REG_NONE) if (obj_priv->fence_reg != I915_FENCE_REG_NONE)
seq_printf(m, " (fence: %d)\n", obj_priv->fence_reg); seq_printf(m, " (fence: %d)", obj_priv->fence_reg);
if (obj_priv->gtt_space != NULL)
seq_printf(m, " (gtt_offset: %08x)", obj_priv->gtt_offset);
seq_printf(m, "\n"); seq_printf(m, "\n");
} }
@ -323,6 +327,39 @@ static int i915_ringbuffer_info(struct seq_file *m, void *data)
return 0; return 0;
} }
static int i915_error_state(struct seq_file *m, void *unused)
{
struct drm_info_node *node = (struct drm_info_node *) m->private;
struct drm_device *dev = node->minor->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_i915_error_state *error;
unsigned long flags;
spin_lock_irqsave(&dev_priv->error_lock, flags);
if (!dev_priv->first_error) {
seq_printf(m, "no error state collected\n");
goto out;
}
error = dev_priv->first_error;
seq_printf(m, "EIR: 0x%08x\n", error->eir);
seq_printf(m, " PGTBL_ER: 0x%08x\n", error->pgtbl_er);
seq_printf(m, " INSTPM: 0x%08x\n", error->instpm);
seq_printf(m, " IPEIR: 0x%08x\n", error->ipeir);
seq_printf(m, " IPEHR: 0x%08x\n", error->ipehr);
seq_printf(m, " INSTDONE: 0x%08x\n", error->instdone);
seq_printf(m, " ACTHD: 0x%08x\n", error->acthd);
if (IS_I965G(dev)) {
seq_printf(m, " INSTPS: 0x%08x\n", error->instps);
seq_printf(m, " INSTDONE1: 0x%08x\n", error->instdone1);
}
out:
spin_unlock_irqrestore(&dev_priv->error_lock, flags);
return 0;
}
static struct drm_info_list i915_gem_debugfs_list[] = { static struct drm_info_list i915_gem_debugfs_list[] = {
{"i915_gem_active", i915_gem_object_list_info, 0, (void *) ACTIVE_LIST}, {"i915_gem_active", i915_gem_object_list_info, 0, (void *) ACTIVE_LIST},
@ -336,6 +373,7 @@ static struct drm_info_list i915_gem_debugfs_list[] = {
{"i915_ringbuffer_data", i915_ringbuffer_data, 0}, {"i915_ringbuffer_data", i915_ringbuffer_data, 0},
{"i915_ringbuffer_info", i915_ringbuffer_info, 0}, {"i915_ringbuffer_info", i915_ringbuffer_info, 0},
{"i915_batchbuffers", i915_batchbuffer_info, 0}, {"i915_batchbuffers", i915_batchbuffer_info, 0},
{"i915_error_state", i915_error_state, 0},
}; };
#define I915_GEM_DEBUGFS_ENTRIES ARRAY_SIZE(i915_gem_debugfs_list) #define I915_GEM_DEBUGFS_ENTRIES ARRAY_SIZE(i915_gem_debugfs_list)

View File

@ -521,6 +521,12 @@ i915_gem_set_tiling(struct drm_device *dev, void *data,
goto err; goto err;
} }
/* If we've changed tiling, GTT-mappings of the object
* need to re-fault to ensure that the correct fence register
* setup is in place.
*/
i915_gem_release_mmap(obj);
obj_priv->tiling_mode = args->tiling_mode; obj_priv->tiling_mode = args->tiling_mode;
obj_priv->stride = args->stride; obj_priv->stride = args->stride;
} }

View File

@ -26,6 +26,7 @@
* *
*/ */
#include <linux/sysrq.h>
#include "drmP.h" #include "drmP.h"
#include "drm.h" #include "drm.h"
#include "i915_drm.h" #include "i915_drm.h"
@ -41,9 +42,10 @@
* we leave them always unmasked in IMR and then control enabling them through * we leave them always unmasked in IMR and then control enabling them through
* PIPESTAT alone. * PIPESTAT alone.
*/ */
#define I915_INTERRUPT_ENABLE_FIX (I915_ASLE_INTERRUPT | \ #define I915_INTERRUPT_ENABLE_FIX (I915_ASLE_INTERRUPT | \
I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | \ I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | \
I915_DISPLAY_PIPE_B_EVENT_INTERRUPT) I915_DISPLAY_PIPE_B_EVENT_INTERRUPT | \
I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT)
/** Interrupts that we mask and unmask at runtime. */ /** Interrupts that we mask and unmask at runtime. */
#define I915_INTERRUPT_ENABLE_VAR (I915_USER_INTERRUPT) #define I915_INTERRUPT_ENABLE_VAR (I915_USER_INTERRUPT)
@ -288,6 +290,47 @@ irqreturn_t igdng_irq_handler(struct drm_device *dev)
return ret; return ret;
} }
static void i915_capture_error_state(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_i915_error_state *error;
unsigned long flags;
spin_lock_irqsave(&dev_priv->error_lock, flags);
if (dev_priv->first_error)
goto out;
error = kmalloc(sizeof(*error), GFP_ATOMIC);
if (!error) {
DRM_DEBUG("out ot memory, not capturing error state\n");
goto out;
}
error->eir = I915_READ(EIR);
error->pgtbl_er = I915_READ(PGTBL_ER);
error->pipeastat = I915_READ(PIPEASTAT);
error->pipebstat = I915_READ(PIPEBSTAT);
error->instpm = I915_READ(INSTPM);
if (!IS_I965G(dev)) {
error->ipeir = I915_READ(IPEIR);
error->ipehr = I915_READ(IPEHR);
error->instdone = I915_READ(INSTDONE);
error->acthd = I915_READ(ACTHD);
} else {
error->ipeir = I915_READ(IPEIR_I965);
error->ipehr = I915_READ(IPEHR_I965);
error->instdone = I915_READ(INSTDONE_I965);
error->instps = I915_READ(INSTPS);
error->instdone1 = I915_READ(INSTDONE1);
error->acthd = I915_READ(ACTHD_I965);
}
dev_priv->first_error = error;
out:
spin_unlock_irqrestore(&dev_priv->error_lock, flags);
}
irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
{ {
struct drm_device *dev = (struct drm_device *) arg; struct drm_device *dev = (struct drm_device *) arg;
@ -333,11 +376,15 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
* Clear the PIPE(A|B)STAT regs before the IIR * Clear the PIPE(A|B)STAT regs before the IIR
*/ */
if (pipea_stats & 0x8000ffff) { if (pipea_stats & 0x8000ffff) {
if (pipea_stats & PIPE_FIFO_UNDERRUN_STATUS)
DRM_DEBUG("pipe a underrun\n");
I915_WRITE(PIPEASTAT, pipea_stats); I915_WRITE(PIPEASTAT, pipea_stats);
irq_received = 1; irq_received = 1;
} }
if (pipeb_stats & 0x8000ffff) { if (pipeb_stats & 0x8000ffff) {
if (pipeb_stats & PIPE_FIFO_UNDERRUN_STATUS)
DRM_DEBUG("pipe b underrun\n");
I915_WRITE(PIPEBSTAT, pipeb_stats); I915_WRITE(PIPEBSTAT, pipeb_stats);
irq_received = 1; irq_received = 1;
} }
@ -362,6 +409,80 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
I915_READ(PORT_HOTPLUG_STAT); I915_READ(PORT_HOTPLUG_STAT);
} }
if (iir & I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT) {
u32 eir = I915_READ(EIR);
i915_capture_error_state(dev);
printk(KERN_ERR "render error detected, EIR: 0x%08x\n",
eir);
if (eir & I915_ERROR_PAGE_TABLE) {
u32 pgtbl_err = I915_READ(PGTBL_ER);
printk(KERN_ERR "page table error\n");
printk(KERN_ERR " PGTBL_ER: 0x%08x\n",
pgtbl_err);
I915_WRITE(PGTBL_ER, pgtbl_err);
(void)I915_READ(PGTBL_ER);
}
if (eir & I915_ERROR_MEMORY_REFRESH) {
printk(KERN_ERR "memory refresh error\n");
printk(KERN_ERR "PIPEASTAT: 0x%08x\n",
pipea_stats);
printk(KERN_ERR "PIPEBSTAT: 0x%08x\n",
pipeb_stats);
/* pipestat has already been acked */
}
if (eir & I915_ERROR_INSTRUCTION) {
printk(KERN_ERR "instruction error\n");
printk(KERN_ERR " INSTPM: 0x%08x\n",
I915_READ(INSTPM));
if (!IS_I965G(dev)) {
u32 ipeir = I915_READ(IPEIR);
printk(KERN_ERR " IPEIR: 0x%08x\n",
I915_READ(IPEIR));
printk(KERN_ERR " IPEHR: 0x%08x\n",
I915_READ(IPEHR));
printk(KERN_ERR " INSTDONE: 0x%08x\n",
I915_READ(INSTDONE));
printk(KERN_ERR " ACTHD: 0x%08x\n",
I915_READ(ACTHD));
I915_WRITE(IPEIR, ipeir);
(void)I915_READ(IPEIR);
} else {
u32 ipeir = I915_READ(IPEIR_I965);
printk(KERN_ERR " IPEIR: 0x%08x\n",
I915_READ(IPEIR_I965));
printk(KERN_ERR " IPEHR: 0x%08x\n",
I915_READ(IPEHR_I965));
printk(KERN_ERR " INSTDONE: 0x%08x\n",
I915_READ(INSTDONE_I965));
printk(KERN_ERR " INSTPS: 0x%08x\n",
I915_READ(INSTPS));
printk(KERN_ERR " INSTDONE1: 0x%08x\n",
I915_READ(INSTDONE1));
printk(KERN_ERR " ACTHD: 0x%08x\n",
I915_READ(ACTHD_I965));
I915_WRITE(IPEIR_I965, ipeir);
(void)I915_READ(IPEIR_I965);
}
}
I915_WRITE(EIR, eir);
(void)I915_READ(EIR);
eir = I915_READ(EIR);
if (eir) {
/*
* some errors might have become stuck,
* mask them.
*/
DRM_ERROR("EIR stuck: 0x%08x, masking\n", eir);
I915_WRITE(EMR, I915_READ(EMR) | eir);
I915_WRITE(IIR, I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT);
}
}
I915_WRITE(IIR, iir); I915_WRITE(IIR, iir);
new_iir = I915_READ(IIR); /* Flush posted writes */ new_iir = I915_READ(IIR); /* Flush posted writes */
@ -732,6 +853,7 @@ int i915_driver_irq_postinstall(struct drm_device *dev)
{ {
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
u32 enable_mask = I915_INTERRUPT_ENABLE_FIX | I915_INTERRUPT_ENABLE_VAR; u32 enable_mask = I915_INTERRUPT_ENABLE_FIX | I915_INTERRUPT_ENABLE_VAR;
u32 error_mask;
DRM_INIT_WAITQUEUE(&dev_priv->irq_queue); DRM_INIT_WAITQUEUE(&dev_priv->irq_queue);
@ -768,6 +890,21 @@ int i915_driver_irq_postinstall(struct drm_device *dev)
i915_enable_irq(dev_priv, I915_DISPLAY_PORT_INTERRUPT); i915_enable_irq(dev_priv, I915_DISPLAY_PORT_INTERRUPT);
} }
/*
* Enable some error detection, note the instruction error mask
* bit is reserved, so we leave it masked.
*/
if (IS_G4X(dev)) {
error_mask = ~(GM45_ERROR_PAGE_TABLE |
GM45_ERROR_MEM_PRIV |
GM45_ERROR_CP_PRIV |
I915_ERROR_MEMORY_REFRESH);
} else {
error_mask = ~(I915_ERROR_PAGE_TABLE |
I915_ERROR_MEMORY_REFRESH);
}
I915_WRITE(EMR, error_mask);
/* Disable pipe interrupt enables, clear pending pipe status */ /* Disable pipe interrupt enables, clear pending pipe status */
I915_WRITE(PIPEASTAT, I915_READ(PIPEASTAT) & 0x8000ffff); I915_WRITE(PIPEASTAT, I915_READ(PIPEASTAT) & 0x8000ffff);
I915_WRITE(PIPEBSTAT, I915_READ(PIPEBSTAT) & 0x8000ffff); I915_WRITE(PIPEBSTAT, I915_READ(PIPEBSTAT) & 0x8000ffff);

View File

@ -206,6 +206,7 @@
/* /*
* Instruction and interrupt control regs * Instruction and interrupt control regs
*/ */
#define PGTBL_ER 0x02024
#define PRB0_TAIL 0x02030 #define PRB0_TAIL 0x02030
#define PRB0_HEAD 0x02034 #define PRB0_HEAD 0x02034
#define PRB0_START 0x02038 #define PRB0_START 0x02038
@ -226,11 +227,18 @@
#define PRB1_HEAD 0x02044 /* 915+ only */ #define PRB1_HEAD 0x02044 /* 915+ only */
#define PRB1_START 0x02048 /* 915+ only */ #define PRB1_START 0x02048 /* 915+ only */
#define PRB1_CTL 0x0204c /* 915+ only */ #define PRB1_CTL 0x0204c /* 915+ only */
#define IPEIR_I965 0x02064
#define IPEHR_I965 0x02068
#define INSTDONE_I965 0x0206c
#define INSTPS 0x02070 /* 965+ only */
#define INSTDONE1 0x0207c /* 965+ only */
#define ACTHD_I965 0x02074 #define ACTHD_I965 0x02074
#define HWS_PGA 0x02080 #define HWS_PGA 0x02080
#define HWS_ADDRESS_MASK 0xfffff000 #define HWS_ADDRESS_MASK 0xfffff000
#define HWS_START_ADDRESS_SHIFT 4 #define HWS_START_ADDRESS_SHIFT 4
#define IPEIR 0x02088 #define IPEIR 0x02088
#define IPEHR 0x0208c
#define INSTDONE 0x02090
#define NOPID 0x02094 #define NOPID 0x02094
#define HWSTAM 0x02098 #define HWSTAM 0x02098
#define SCPD0 0x0209c /* 915+ only */ #define SCPD0 0x0209c /* 915+ only */
@ -258,10 +266,22 @@
#define EIR 0x020b0 #define EIR 0x020b0
#define EMR 0x020b4 #define EMR 0x020b4
#define ESR 0x020b8 #define ESR 0x020b8
#define GM45_ERROR_PAGE_TABLE (1<<5)
#define GM45_ERROR_MEM_PRIV (1<<4)
#define I915_ERROR_PAGE_TABLE (1<<4)
#define GM45_ERROR_CP_PRIV (1<<3)
#define I915_ERROR_MEMORY_REFRESH (1<<1)
#define I915_ERROR_INSTRUCTION (1<<0)
#define INSTPM 0x020c0 #define INSTPM 0x020c0
#define ACTHD 0x020c8 #define ACTHD 0x020c8
#define FW_BLC 0x020d8 #define FW_BLC 0x020d8
#define FW_BLC2 0x020dc
#define FW_BLC_SELF 0x020e0 /* 915+ only */ #define FW_BLC_SELF 0x020e0 /* 915+ only */
#define FW_BLC_SELF_EN (1<<15)
#define MM_BURST_LENGTH 0x00700000
#define MM_FIFO_WATERMARK 0x0001F000
#define LM_BURST_LENGTH 0x00000700
#define LM_FIFO_WATERMARK 0x0000001F
#define MI_ARB_STATE 0x020e4 /* 915+ only */ #define MI_ARB_STATE 0x020e4 /* 915+ only */
#define CACHE_MODE_0 0x02120 /* 915+ only */ #define CACHE_MODE_0 0x02120 /* 915+ only */
#define CM0_MASK_SHIFT 16 #define CM0_MASK_SHIFT 16
@ -571,17 +591,21 @@
/* Clocking configuration register */ /* Clocking configuration register */
#define CLKCFG 0x10c00 #define CLKCFG 0x10c00
#define CLKCFG_FSB_400 (0 << 0) /* hrawclk 100 */ #define CLKCFG_FSB_400 (5 << 0) /* hrawclk 100 */
#define CLKCFG_FSB_533 (1 << 0) /* hrawclk 133 */ #define CLKCFG_FSB_533 (1 << 0) /* hrawclk 133 */
#define CLKCFG_FSB_667 (3 << 0) /* hrawclk 166 */ #define CLKCFG_FSB_667 (3 << 0) /* hrawclk 166 */
#define CLKCFG_FSB_800 (2 << 0) /* hrawclk 200 */ #define CLKCFG_FSB_800 (2 << 0) /* hrawclk 200 */
#define CLKCFG_FSB_1067 (6 << 0) /* hrawclk 266 */ #define CLKCFG_FSB_1067 (6 << 0) /* hrawclk 266 */
#define CLKCFG_FSB_1333 (7 << 0) /* hrawclk 333 */ #define CLKCFG_FSB_1333 (7 << 0) /* hrawclk 333 */
/* this is a guess, could be 5 as well */ /* Note, below two are guess */
#define CLKCFG_FSB_1600 (4 << 0) /* hrawclk 400 */ #define CLKCFG_FSB_1600 (4 << 0) /* hrawclk 400 */
#define CLKCFG_FSB_1600_ALT (5 << 0) /* hrawclk 400 */ #define CLKCFG_FSB_1600_ALT (0 << 0) /* hrawclk 400 */
#define CLKCFG_FSB_MASK (7 << 0) #define CLKCFG_FSB_MASK (7 << 0)
#define CLKCFG_MEM_533 (1 << 4)
#define CLKCFG_MEM_667 (2 << 4)
#define CLKCFG_MEM_800 (3 << 4)
#define CLKCFG_MEM_MASK (7 << 4)
/** GM965 GM45 render standby register */ /** GM965 GM45 render standby register */
#define MCHBAR_RENDER_STANDBY 0x111B8 #define MCHBAR_RENDER_STANDBY 0x111B8
@ -1581,6 +1605,34 @@
#define DSPARB_CSTART_SHIFT 7 #define DSPARB_CSTART_SHIFT 7
#define DSPARB_BSTART_MASK (0x7f) #define DSPARB_BSTART_MASK (0x7f)
#define DSPARB_BSTART_SHIFT 0 #define DSPARB_BSTART_SHIFT 0
#define DSPARB_BEND_SHIFT 9 /* on 855 */
#define DSPARB_AEND_SHIFT 0
#define DSPFW1 0x70034
#define DSPFW2 0x70038
#define DSPFW3 0x7003c
#define IGD_SELF_REFRESH_EN (1<<30)
/* FIFO watermark sizes etc */
#define I915_FIFO_LINE_SIZE 64
#define I830_FIFO_LINE_SIZE 32
#define I945_FIFO_SIZE 127 /* 945 & 965 */
#define I915_FIFO_SIZE 95
#define I855GM_FIFO_SIZE 255
#define I830_FIFO_SIZE 95
#define I915_MAX_WM 0x3f
#define IGD_DISPLAY_FIFO 512 /* in 64byte unit */
#define IGD_FIFO_LINE_SIZE 64
#define IGD_MAX_WM 0x1ff
#define IGD_DFT_WM 0x3f
#define IGD_DFT_HPLLOFF_WM 0
#define IGD_GUARD_WM 10
#define IGD_CURSOR_FIFO 64
#define IGD_CURSOR_MAX_WM 0x3f
#define IGD_CURSOR_DFT_WM 0
#define IGD_CURSOR_GUARD_WM 5
/* /*
* The two pipe frame counter registers are not synchronized, so * The two pipe frame counter registers are not synchronized, so
* reading a stable value is somewhat tricky. The following code * reading a stable value is somewhat tricky. The following code

View File

@ -222,23 +222,12 @@ static void i915_restore_vga(struct drm_device *dev)
I915_WRITE8(VGA_DACMASK, dev_priv->saveDACMASK); I915_WRITE8(VGA_DACMASK, dev_priv->saveDACMASK);
} }
int i915_save_state(struct drm_device *dev) static void i915_save_modeset_reg(struct drm_device *dev)
{ {
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
int i;
pci_read_config_byte(dev->pdev, LBB, &dev_priv->saveLBB);
/* Render Standby */
if (IS_I965G(dev) && IS_MOBILE(dev))
dev_priv->saveRENDERSTANDBY = I915_READ(MCHBAR_RENDER_STANDBY);
/* Hardware status page */
dev_priv->saveHWS = I915_READ(HWS_PGA);
/* Display arbitration control */
dev_priv->saveDSPARB = I915_READ(DSPARB);
if (drm_core_check_feature(dev, DRIVER_MODESET))
return;
/* Pipe & plane A info */ /* Pipe & plane A info */
dev_priv->savePIPEACONF = I915_READ(PIPEACONF); dev_priv->savePIPEACONF = I915_READ(PIPEACONF);
dev_priv->savePIPEASRC = I915_READ(PIPEASRC); dev_priv->savePIPEASRC = I915_READ(PIPEASRC);
@ -294,7 +283,122 @@ int i915_save_state(struct drm_device *dev)
} }
i915_save_palette(dev, PIPE_B); i915_save_palette(dev, PIPE_B);
dev_priv->savePIPEBSTAT = I915_READ(PIPEBSTAT); dev_priv->savePIPEBSTAT = I915_READ(PIPEBSTAT);
return;
}
static void i915_restore_modeset_reg(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
if (drm_core_check_feature(dev, DRIVER_MODESET))
return;
/* Pipe & plane A info */
/* Prime the clock */
if (dev_priv->saveDPLL_A & DPLL_VCO_ENABLE) {
I915_WRITE(DPLL_A, dev_priv->saveDPLL_A &
~DPLL_VCO_ENABLE);
DRM_UDELAY(150);
}
I915_WRITE(FPA0, dev_priv->saveFPA0);
I915_WRITE(FPA1, dev_priv->saveFPA1);
/* Actually enable it */
I915_WRITE(DPLL_A, dev_priv->saveDPLL_A);
DRM_UDELAY(150);
if (IS_I965G(dev))
I915_WRITE(DPLL_A_MD, dev_priv->saveDPLL_A_MD);
DRM_UDELAY(150);
/* Restore mode */
I915_WRITE(HTOTAL_A, dev_priv->saveHTOTAL_A);
I915_WRITE(HBLANK_A, dev_priv->saveHBLANK_A);
I915_WRITE(HSYNC_A, dev_priv->saveHSYNC_A);
I915_WRITE(VTOTAL_A, dev_priv->saveVTOTAL_A);
I915_WRITE(VBLANK_A, dev_priv->saveVBLANK_A);
I915_WRITE(VSYNC_A, dev_priv->saveVSYNC_A);
I915_WRITE(BCLRPAT_A, dev_priv->saveBCLRPAT_A);
/* Restore plane info */
I915_WRITE(DSPASIZE, dev_priv->saveDSPASIZE);
I915_WRITE(DSPAPOS, dev_priv->saveDSPAPOS);
I915_WRITE(PIPEASRC, dev_priv->savePIPEASRC);
I915_WRITE(DSPAADDR, dev_priv->saveDSPAADDR);
I915_WRITE(DSPASTRIDE, dev_priv->saveDSPASTRIDE);
if (IS_I965G(dev)) {
I915_WRITE(DSPASURF, dev_priv->saveDSPASURF);
I915_WRITE(DSPATILEOFF, dev_priv->saveDSPATILEOFF);
}
I915_WRITE(PIPEACONF, dev_priv->savePIPEACONF);
i915_restore_palette(dev, PIPE_A);
/* Enable the plane */
I915_WRITE(DSPACNTR, dev_priv->saveDSPACNTR);
I915_WRITE(DSPAADDR, I915_READ(DSPAADDR));
/* Pipe & plane B info */
if (dev_priv->saveDPLL_B & DPLL_VCO_ENABLE) {
I915_WRITE(DPLL_B, dev_priv->saveDPLL_B &
~DPLL_VCO_ENABLE);
DRM_UDELAY(150);
}
I915_WRITE(FPB0, dev_priv->saveFPB0);
I915_WRITE(FPB1, dev_priv->saveFPB1);
/* Actually enable it */
I915_WRITE(DPLL_B, dev_priv->saveDPLL_B);
DRM_UDELAY(150);
if (IS_I965G(dev))
I915_WRITE(DPLL_B_MD, dev_priv->saveDPLL_B_MD);
DRM_UDELAY(150);
/* Restore mode */
I915_WRITE(HTOTAL_B, dev_priv->saveHTOTAL_B);
I915_WRITE(HBLANK_B, dev_priv->saveHBLANK_B);
I915_WRITE(HSYNC_B, dev_priv->saveHSYNC_B);
I915_WRITE(VTOTAL_B, dev_priv->saveVTOTAL_B);
I915_WRITE(VBLANK_B, dev_priv->saveVBLANK_B);
I915_WRITE(VSYNC_B, dev_priv->saveVSYNC_B);
I915_WRITE(BCLRPAT_B, dev_priv->saveBCLRPAT_B);
/* Restore plane info */
I915_WRITE(DSPBSIZE, dev_priv->saveDSPBSIZE);
I915_WRITE(DSPBPOS, dev_priv->saveDSPBPOS);
I915_WRITE(PIPEBSRC, dev_priv->savePIPEBSRC);
I915_WRITE(DSPBADDR, dev_priv->saveDSPBADDR);
I915_WRITE(DSPBSTRIDE, dev_priv->saveDSPBSTRIDE);
if (IS_I965G(dev)) {
I915_WRITE(DSPBSURF, dev_priv->saveDSPBSURF);
I915_WRITE(DSPBTILEOFF, dev_priv->saveDSPBTILEOFF);
}
I915_WRITE(PIPEBCONF, dev_priv->savePIPEBCONF);
i915_restore_palette(dev, PIPE_B);
/* Enable the plane */
I915_WRITE(DSPBCNTR, dev_priv->saveDSPBCNTR);
I915_WRITE(DSPBADDR, I915_READ(DSPBADDR));
return;
}
int i915_save_state(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
int i;
pci_read_config_byte(dev->pdev, LBB, &dev_priv->saveLBB);
/* Render Standby */
if (IS_I965G(dev) && IS_MOBILE(dev))
dev_priv->saveRENDERSTANDBY = I915_READ(MCHBAR_RENDER_STANDBY);
/* Hardware status page */
dev_priv->saveHWS = I915_READ(HWS_PGA);
/* Display arbitration control */
dev_priv->saveDSPARB = I915_READ(DSPARB);
/* This is only meaningful in non-KMS mode */
/* Don't save them in KMS mode */
i915_save_modeset_reg(dev);
/* Cursor state */ /* Cursor state */
dev_priv->saveCURACNTR = I915_READ(CURACNTR); dev_priv->saveCURACNTR = I915_READ(CURACNTR);
dev_priv->saveCURAPOS = I915_READ(CURAPOS); dev_priv->saveCURAPOS = I915_READ(CURAPOS);
@ -430,92 +534,9 @@ int i915_restore_state(struct drm_device *dev)
I915_WRITE(PIPEA_DP_LINK_N, dev_priv->savePIPEA_DP_LINK_N); I915_WRITE(PIPEA_DP_LINK_N, dev_priv->savePIPEA_DP_LINK_N);
I915_WRITE(PIPEB_DP_LINK_N, dev_priv->savePIPEB_DP_LINK_N); I915_WRITE(PIPEB_DP_LINK_N, dev_priv->savePIPEB_DP_LINK_N);
} }
/* This is only meaningful in non-KMS mode */
/* Pipe & plane A info */ /* Don't restore them in KMS mode */
/* Prime the clock */ i915_restore_modeset_reg(dev);
if (dev_priv->saveDPLL_A & DPLL_VCO_ENABLE) {
I915_WRITE(DPLL_A, dev_priv->saveDPLL_A &
~DPLL_VCO_ENABLE);
DRM_UDELAY(150);
}
I915_WRITE(FPA0, dev_priv->saveFPA0);
I915_WRITE(FPA1, dev_priv->saveFPA1);
/* Actually enable it */
I915_WRITE(DPLL_A, dev_priv->saveDPLL_A);
DRM_UDELAY(150);
if (IS_I965G(dev))
I915_WRITE(DPLL_A_MD, dev_priv->saveDPLL_A_MD);
DRM_UDELAY(150);
/* Restore mode */
I915_WRITE(HTOTAL_A, dev_priv->saveHTOTAL_A);
I915_WRITE(HBLANK_A, dev_priv->saveHBLANK_A);
I915_WRITE(HSYNC_A, dev_priv->saveHSYNC_A);
I915_WRITE(VTOTAL_A, dev_priv->saveVTOTAL_A);
I915_WRITE(VBLANK_A, dev_priv->saveVBLANK_A);
I915_WRITE(VSYNC_A, dev_priv->saveVSYNC_A);
I915_WRITE(BCLRPAT_A, dev_priv->saveBCLRPAT_A);
/* Restore plane info */
I915_WRITE(DSPASIZE, dev_priv->saveDSPASIZE);
I915_WRITE(DSPAPOS, dev_priv->saveDSPAPOS);
I915_WRITE(PIPEASRC, dev_priv->savePIPEASRC);
I915_WRITE(DSPAADDR, dev_priv->saveDSPAADDR);
I915_WRITE(DSPASTRIDE, dev_priv->saveDSPASTRIDE);
if (IS_I965G(dev)) {
I915_WRITE(DSPASURF, dev_priv->saveDSPASURF);
I915_WRITE(DSPATILEOFF, dev_priv->saveDSPATILEOFF);
}
I915_WRITE(PIPEACONF, dev_priv->savePIPEACONF);
i915_restore_palette(dev, PIPE_A);
/* Enable the plane */
I915_WRITE(DSPACNTR, dev_priv->saveDSPACNTR);
I915_WRITE(DSPAADDR, I915_READ(DSPAADDR));
/* Pipe & plane B info */
if (dev_priv->saveDPLL_B & DPLL_VCO_ENABLE) {
I915_WRITE(DPLL_B, dev_priv->saveDPLL_B &
~DPLL_VCO_ENABLE);
DRM_UDELAY(150);
}
I915_WRITE(FPB0, dev_priv->saveFPB0);
I915_WRITE(FPB1, dev_priv->saveFPB1);
/* Actually enable it */
I915_WRITE(DPLL_B, dev_priv->saveDPLL_B);
DRM_UDELAY(150);
if (IS_I965G(dev))
I915_WRITE(DPLL_B_MD, dev_priv->saveDPLL_B_MD);
DRM_UDELAY(150);
/* Restore mode */
I915_WRITE(HTOTAL_B, dev_priv->saveHTOTAL_B);
I915_WRITE(HBLANK_B, dev_priv->saveHBLANK_B);
I915_WRITE(HSYNC_B, dev_priv->saveHSYNC_B);
I915_WRITE(VTOTAL_B, dev_priv->saveVTOTAL_B);
I915_WRITE(VBLANK_B, dev_priv->saveVBLANK_B);
I915_WRITE(VSYNC_B, dev_priv->saveVSYNC_B);
I915_WRITE(BCLRPAT_B, dev_priv->saveBCLRPAT_B);
/* Restore plane info */
I915_WRITE(DSPBSIZE, dev_priv->saveDSPBSIZE);
I915_WRITE(DSPBPOS, dev_priv->saveDSPBPOS);
I915_WRITE(PIPEBSRC, dev_priv->savePIPEBSRC);
I915_WRITE(DSPBADDR, dev_priv->saveDSPBADDR);
I915_WRITE(DSPBSTRIDE, dev_priv->saveDSPBSTRIDE);
if (IS_I965G(dev)) {
I915_WRITE(DSPBSURF, dev_priv->saveDSPBSURF);
I915_WRITE(DSPBTILEOFF, dev_priv->saveDSPBTILEOFF);
}
I915_WRITE(PIPEBCONF, dev_priv->savePIPEBCONF);
i915_restore_palette(dev, PIPE_B);
/* Enable the plane */
I915_WRITE(DSPBCNTR, dev_priv->saveDSPBCNTR);
I915_WRITE(DSPBADDR, I915_READ(DSPBADDR));
/* Cursor state */ /* Cursor state */
I915_WRITE(CURAPOS, dev_priv->saveCURAPOS); I915_WRITE(CURAPOS, dev_priv->saveCURAPOS);
I915_WRITE(CURACNTR, dev_priv->saveCURACNTR); I915_WRITE(CURACNTR, dev_priv->saveCURACNTR);

View File

@ -97,6 +97,7 @@ static void
parse_lfp_panel_data(struct drm_i915_private *dev_priv, parse_lfp_panel_data(struct drm_i915_private *dev_priv,
struct bdb_header *bdb) struct bdb_header *bdb)
{ {
struct drm_device *dev = dev_priv->dev;
struct bdb_lvds_options *lvds_options; struct bdb_lvds_options *lvds_options;
struct bdb_lvds_lfp_data *lvds_lfp_data; struct bdb_lvds_lfp_data *lvds_lfp_data;
struct bdb_lvds_lfp_data_ptrs *lvds_lfp_data_ptrs; struct bdb_lvds_lfp_data_ptrs *lvds_lfp_data_ptrs;
@ -132,7 +133,14 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv,
entry = (struct bdb_lvds_lfp_data_entry *) entry = (struct bdb_lvds_lfp_data_entry *)
((uint8_t *)lvds_lfp_data->data + (lfp_data_size * ((uint8_t *)lvds_lfp_data->data + (lfp_data_size *
lvds_options->panel_type)); lvds_options->panel_type));
dvo_timing = &entry->dvo_timing;
/* On IGDNG mobile, LVDS data block removes panel fitting registers.
So dec 2 dword from dvo_timing offset */
if (IS_IGDNG(dev))
dvo_timing = (struct lvds_dvo_timing *)
((u8 *)&entry->dvo_timing - 8);
else
dvo_timing = &entry->dvo_timing;
panel_fixed_mode = kzalloc(sizeof(*panel_fixed_mode), GFP_KERNEL); panel_fixed_mode = kzalloc(sizeof(*panel_fixed_mode), GFP_KERNEL);
@ -195,10 +203,12 @@ parse_general_features(struct drm_i915_private *dev_priv,
dev_priv->lvds_use_ssc = general->enable_ssc; dev_priv->lvds_use_ssc = general->enable_ssc;
if (dev_priv->lvds_use_ssc) { if (dev_priv->lvds_use_ssc) {
if (IS_I855(dev_priv->dev)) if (IS_I85X(dev_priv->dev))
dev_priv->lvds_ssc_freq = general->ssc_freq ? 66 : 48; dev_priv->lvds_ssc_freq =
else general->ssc_freq ? 66 : 48;
dev_priv->lvds_ssc_freq = general->ssc_freq ? 100 : 96; else
dev_priv->lvds_ssc_freq =
general->ssc_freq ? 100 : 96;
} }
} }
} }

View File

@ -46,7 +46,7 @@ static void intel_crt_dpms(struct drm_encoder *encoder, int mode)
temp = I915_READ(reg); temp = I915_READ(reg);
temp &= ~(ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE); temp &= ~(ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE);
temp |= ADPA_DAC_ENABLE; temp &= ~ADPA_DAC_ENABLE;
switch(mode) { switch(mode) {
case DRM_MODE_DPMS_ON: case DRM_MODE_DPMS_ON:
@ -428,8 +428,34 @@ static void intel_crt_destroy(struct drm_connector *connector)
static int intel_crt_get_modes(struct drm_connector *connector) static int intel_crt_get_modes(struct drm_connector *connector)
{ {
int ret;
struct intel_output *intel_output = to_intel_output(connector); struct intel_output *intel_output = to_intel_output(connector);
return intel_ddc_get_modes(intel_output); struct i2c_adapter *ddcbus;
struct drm_device *dev = connector->dev;
ret = intel_ddc_get_modes(intel_output);
if (ret || !IS_G4X(dev))
goto end;
ddcbus = intel_output->ddc_bus;
/* Try to probe digital port for output in DVI-I -> VGA mode. */
intel_output->ddc_bus =
intel_i2c_create(connector->dev, GPIOD, "CRTDDC_D");
if (!intel_output->ddc_bus) {
intel_output->ddc_bus = ddcbus;
dev_printk(KERN_ERR, &connector->dev->pdev->dev,
"DDC bus registration failed for CRTDDC_D.\n");
goto end;
}
/* Try to get modes by GPIOD port */
ret = intel_ddc_get_modes(intel_output);
intel_i2c_destroy(ddcbus);
end:
return ret;
} }
static int intel_crt_set_property(struct drm_connector *connector, static int intel_crt_set_property(struct drm_connector *connector,

View File

@ -25,6 +25,7 @@
*/ */
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/kernel.h>
#include "drmP.h" #include "drmP.h"
#include "intel_drv.h" #include "intel_drv.h"
#include "i915_drm.h" #include "i915_drm.h"
@ -34,6 +35,7 @@
#include "drm_crtc_helper.h" #include "drm_crtc_helper.h"
bool intel_pipe_has_type (struct drm_crtc *crtc, int type); bool intel_pipe_has_type (struct drm_crtc *crtc, int type);
static void intel_update_watermarks(struct drm_device *dev);
typedef struct { typedef struct {
/* given values */ /* given values */
@ -814,24 +816,21 @@ intel_find_pll_g4x_dp(const intel_limit_t *limit, struct drm_crtc *crtc,
{ {
intel_clock_t clock; intel_clock_t clock;
if (target < 200000) { if (target < 200000) {
clock.dot = 161670;
clock.p = 20;
clock.p1 = 2; clock.p1 = 2;
clock.p2 = 10; clock.p2 = 10;
clock.n = 0x01; clock.n = 2;
clock.m = 97; clock.m1 = 23;
clock.m1 = 0x10; clock.m2 = 8;
clock.m2 = 0x05;
} else { } else {
clock.dot = 270000;
clock.p = 10;
clock.p1 = 1; clock.p1 = 1;
clock.p2 = 10; clock.p2 = 10;
clock.n = 0x02; clock.n = 1;
clock.m = 108; clock.m1 = 14;
clock.m1 = 0x12; clock.m2 = 2;
clock.m2 = 0x06;
} }
clock.m = 5 * (clock.m1 + 2) + (clock.m2 + 2);
clock.p = (clock.p1 * clock.p2);
clock.dot = 96000 * clock.m / (clock.n + 2) / clock.p;
memcpy(best_clock, &clock, sizeof(intel_clock_t)); memcpy(best_clock, &clock, sizeof(intel_clock_t));
return true; return true;
} }
@ -1005,7 +1004,7 @@ static void igdng_crtc_dpms(struct drm_crtc *crtc, int mode)
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc); struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
int pipe = intel_crtc->pipe; int pipe = intel_crtc->pipe;
int plane = intel_crtc->pipe; int plane = intel_crtc->plane;
int pch_dpll_reg = (pipe == 0) ? PCH_DPLL_A : PCH_DPLL_B; int pch_dpll_reg = (pipe == 0) ? PCH_DPLL_A : PCH_DPLL_B;
int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF; int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF;
int dspcntr_reg = (plane == 0) ? DSPACNTR : DSPBCNTR; int dspcntr_reg = (plane == 0) ? DSPACNTR : DSPBCNTR;
@ -1335,8 +1334,10 @@ static void i9xx_crtc_dpms(struct drm_crtc *crtc, int mode)
/* Give the overlay scaler a chance to enable if it's on this pipe */ /* Give the overlay scaler a chance to enable if it's on this pipe */
//intel_crtc_dpms_video(crtc, true); TODO //intel_crtc_dpms_video(crtc, true); TODO
intel_update_watermarks(dev);
break; break;
case DRM_MODE_DPMS_OFF: case DRM_MODE_DPMS_OFF:
intel_update_watermarks(dev);
/* Give the overlay scaler a chance to disable if it's on this pipe */ /* Give the overlay scaler a chance to disable if it's on this pipe */
//intel_crtc_dpms_video(crtc, FALSE); TODO //intel_crtc_dpms_video(crtc, FALSE); TODO
@ -1515,7 +1516,6 @@ static int intel_get_core_clock_speed(struct drm_device *dev)
return 0; /* Silence gcc warning */ return 0; /* Silence gcc warning */
} }
/** /**
* Return the pipe currently connected to the panel fitter, * Return the pipe currently connected to the panel fitter,
* or -1 if the panel fitter is not present or not in use * or -1 if the panel fitter is not present or not in use
@ -1574,7 +1574,7 @@ igdng_compute_m_n(int bytes_per_pixel, int nlanes,
temp = (u64) DATA_N * pixel_clock; temp = (u64) DATA_N * pixel_clock;
temp = div_u64(temp, link_clock); temp = div_u64(temp, link_clock);
m_n->gmch_m = (temp * bytes_per_pixel) / nlanes; m_n->gmch_m = div_u64(temp * bytes_per_pixel, nlanes);
m_n->gmch_n = DATA_N; m_n->gmch_n = DATA_N;
fdi_reduce_ratio(&m_n->gmch_m, &m_n->gmch_n); fdi_reduce_ratio(&m_n->gmch_m, &m_n->gmch_n);
@ -1585,6 +1585,420 @@ igdng_compute_m_n(int bytes_per_pixel, int nlanes,
} }
struct intel_watermark_params {
unsigned long fifo_size;
unsigned long max_wm;
unsigned long default_wm;
unsigned long guard_size;
unsigned long cacheline_size;
};
/* IGD has different values for various configs */
static struct intel_watermark_params igd_display_wm = {
IGD_DISPLAY_FIFO,
IGD_MAX_WM,
IGD_DFT_WM,
IGD_GUARD_WM,
IGD_FIFO_LINE_SIZE
};
static struct intel_watermark_params igd_display_hplloff_wm = {
IGD_DISPLAY_FIFO,
IGD_MAX_WM,
IGD_DFT_HPLLOFF_WM,
IGD_GUARD_WM,
IGD_FIFO_LINE_SIZE
};
static struct intel_watermark_params igd_cursor_wm = {
IGD_CURSOR_FIFO,
IGD_CURSOR_MAX_WM,
IGD_CURSOR_DFT_WM,
IGD_CURSOR_GUARD_WM,
IGD_FIFO_LINE_SIZE,
};
static struct intel_watermark_params igd_cursor_hplloff_wm = {
IGD_CURSOR_FIFO,
IGD_CURSOR_MAX_WM,
IGD_CURSOR_DFT_WM,
IGD_CURSOR_GUARD_WM,
IGD_FIFO_LINE_SIZE
};
static struct intel_watermark_params i945_wm_info = {
I915_FIFO_LINE_SIZE,
I915_MAX_WM,
1,
0,
IGD_FIFO_LINE_SIZE
};
static struct intel_watermark_params i915_wm_info = {
I945_FIFO_SIZE,
I915_MAX_WM,
1,
0,
I915_FIFO_LINE_SIZE
};
static struct intel_watermark_params i855_wm_info = {
I855GM_FIFO_SIZE,
I915_MAX_WM,
1,
0,
I830_FIFO_LINE_SIZE
};
static struct intel_watermark_params i830_wm_info = {
I830_FIFO_SIZE,
I915_MAX_WM,
1,
0,
I830_FIFO_LINE_SIZE
};
static unsigned long intel_calculate_wm(unsigned long clock_in_khz,
struct intel_watermark_params *wm,
int pixel_size,
unsigned long latency_ns)
{
unsigned long bytes_required, wm_size;
bytes_required = (clock_in_khz * pixel_size * latency_ns) / 1000000;
bytes_required /= wm->cacheline_size;
wm_size = wm->fifo_size - bytes_required - wm->guard_size;
if (wm_size > wm->max_wm)
wm_size = wm->max_wm;
if (wm_size == 0)
wm_size = wm->default_wm;
return wm_size;
}
struct cxsr_latency {
int is_desktop;
unsigned long fsb_freq;
unsigned long mem_freq;
unsigned long display_sr;
unsigned long display_hpll_disable;
unsigned long cursor_sr;
unsigned long cursor_hpll_disable;
};
static struct cxsr_latency cxsr_latency_table[] = {
{1, 800, 400, 3382, 33382, 3983, 33983}, /* DDR2-400 SC */
{1, 800, 667, 3354, 33354, 3807, 33807}, /* DDR2-667 SC */
{1, 800, 800, 3347, 33347, 3763, 33763}, /* DDR2-800 SC */
{1, 667, 400, 3400, 33400, 4021, 34021}, /* DDR2-400 SC */
{1, 667, 667, 3372, 33372, 3845, 33845}, /* DDR2-667 SC */
{1, 667, 800, 3386, 33386, 3822, 33822}, /* DDR2-800 SC */
{1, 400, 400, 3472, 33472, 4173, 34173}, /* DDR2-400 SC */
{1, 400, 667, 3443, 33443, 3996, 33996}, /* DDR2-667 SC */
{1, 400, 800, 3430, 33430, 3946, 33946}, /* DDR2-800 SC */
{0, 800, 400, 3438, 33438, 4065, 34065}, /* DDR2-400 SC */
{0, 800, 667, 3410, 33410, 3889, 33889}, /* DDR2-667 SC */
{0, 800, 800, 3403, 33403, 3845, 33845}, /* DDR2-800 SC */
{0, 667, 400, 3456, 33456, 4103, 34106}, /* DDR2-400 SC */
{0, 667, 667, 3428, 33428, 3927, 33927}, /* DDR2-667 SC */
{0, 667, 800, 3443, 33443, 3905, 33905}, /* DDR2-800 SC */
{0, 400, 400, 3528, 33528, 4255, 34255}, /* DDR2-400 SC */
{0, 400, 667, 3500, 33500, 4079, 34079}, /* DDR2-667 SC */
{0, 400, 800, 3487, 33487, 4029, 34029}, /* DDR2-800 SC */
};
static struct cxsr_latency *intel_get_cxsr_latency(int is_desktop, int fsb,
int mem)
{
int i;
struct cxsr_latency *latency;
if (fsb == 0 || mem == 0)
return NULL;
for (i = 0; i < ARRAY_SIZE(cxsr_latency_table); i++) {
latency = &cxsr_latency_table[i];
if (is_desktop == latency->is_desktop &&
fsb == latency->fsb_freq && mem == latency->mem_freq)
break;
}
if (i >= ARRAY_SIZE(cxsr_latency_table)) {
DRM_DEBUG("Unknown FSB/MEM found, disable CxSR\n");
return NULL;
}
return latency;
}
static void igd_disable_cxsr(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
u32 reg;
/* deactivate cxsr */
reg = I915_READ(DSPFW3);
reg &= ~(IGD_SELF_REFRESH_EN);
I915_WRITE(DSPFW3, reg);
DRM_INFO("Big FIFO is disabled\n");
}
static void igd_enable_cxsr(struct drm_device *dev, unsigned long clock,
int pixel_size)
{
struct drm_i915_private *dev_priv = dev->dev_private;
u32 reg;
unsigned long wm;
struct cxsr_latency *latency;
latency = intel_get_cxsr_latency(IS_IGDG(dev), dev_priv->fsb_freq,
dev_priv->mem_freq);
if (!latency) {
DRM_DEBUG("Unknown FSB/MEM found, disable CxSR\n");
igd_disable_cxsr(dev);
return;
}
/* Display SR */
wm = intel_calculate_wm(clock, &igd_display_wm, pixel_size,
latency->display_sr);
reg = I915_READ(DSPFW1);
reg &= 0x7fffff;
reg |= wm << 23;
I915_WRITE(DSPFW1, reg);
DRM_DEBUG("DSPFW1 register is %x\n", reg);
/* cursor SR */
wm = intel_calculate_wm(clock, &igd_cursor_wm, pixel_size,
latency->cursor_sr);
reg = I915_READ(DSPFW3);
reg &= ~(0x3f << 24);
reg |= (wm & 0x3f) << 24;
I915_WRITE(DSPFW3, reg);
/* Display HPLL off SR */
wm = intel_calculate_wm(clock, &igd_display_hplloff_wm,
latency->display_hpll_disable, I915_FIFO_LINE_SIZE);
reg = I915_READ(DSPFW3);
reg &= 0xfffffe00;
reg |= wm & 0x1ff;
I915_WRITE(DSPFW3, reg);
/* cursor HPLL off SR */
wm = intel_calculate_wm(clock, &igd_cursor_hplloff_wm, pixel_size,
latency->cursor_hpll_disable);
reg = I915_READ(DSPFW3);
reg &= ~(0x3f << 16);
reg |= (wm & 0x3f) << 16;
I915_WRITE(DSPFW3, reg);
DRM_DEBUG("DSPFW3 register is %x\n", reg);
/* activate cxsr */
reg = I915_READ(DSPFW3);
reg |= IGD_SELF_REFRESH_EN;
I915_WRITE(DSPFW3, reg);
DRM_INFO("Big FIFO is enabled\n");
return;
}
const static int latency_ns = 5000; /* default for non-igd platforms */
static void i965_update_wm(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
DRM_DEBUG("Setting FIFO watermarks - A: 8, B: 8, C: 8, SR 8\n");
/* 965 has limitations... */
I915_WRITE(DSPFW1, (8 << 16) | (8 << 8) | (8 << 0));
I915_WRITE(DSPFW2, (8 << 8) | (8 << 0));
}
static void i9xx_update_wm(struct drm_device *dev, int planea_clock,
int planeb_clock, int sr_hdisplay, int pixel_size)
{
struct drm_i915_private *dev_priv = dev->dev_private;
uint32_t fwater_lo = I915_READ(FW_BLC) & MM_FIFO_WATERMARK;
uint32_t fwater_hi = I915_READ(FW_BLC2) & LM_FIFO_WATERMARK;
int bsize, asize, cwm, bwm = 1, awm = 1, srwm = 1;
uint32_t dsparb = I915_READ(DSPARB);
int planea_entries, planeb_entries;
struct intel_watermark_params *wm_params;
unsigned long line_time_us;
int sr_clock, sr_entries = 0;
if (IS_I965GM(dev) || IS_I945GM(dev))
wm_params = &i945_wm_info;
else if (IS_I9XX(dev))
wm_params = &i915_wm_info;
else
wm_params = &i855_wm_info;
planea_entries = intel_calculate_wm(planea_clock, wm_params,
pixel_size, latency_ns);
planeb_entries = intel_calculate_wm(planeb_clock, wm_params,
pixel_size, latency_ns);
DRM_DEBUG("FIFO entries - A: %d, B: %d\n", planea_entries,
planeb_entries);
if (IS_I9XX(dev)) {
asize = dsparb & 0x7f;
bsize = (dsparb >> DSPARB_CSTART_SHIFT) & 0x7f;
} else {
asize = dsparb & 0x1ff;
bsize = (dsparb >> DSPARB_BEND_SHIFT) & 0x1ff;
}
DRM_DEBUG("FIFO size - A: %d, B: %d\n", asize, bsize);
/* Two extra entries for padding */
awm = asize - (planea_entries + 2);
bwm = bsize - (planeb_entries + 2);
/* Sanity check against potentially bad FIFO allocations */
if (awm <= 0) {
/* pipe is on but has too few FIFO entries */
if (planea_entries != 0)
DRM_DEBUG("plane A needs more FIFO entries\n");
awm = 1;
}
if (bwm <= 0) {
if (planeb_entries != 0)
DRM_DEBUG("plane B needs more FIFO entries\n");
bwm = 1;
}
/*
* Overlay gets an aggressive default since video jitter is bad.
*/
cwm = 2;
/* Calc sr entries for one pipe configs */
if (!planea_clock || !planeb_clock) {
sr_clock = planea_clock ? planea_clock : planeb_clock;
line_time_us = (sr_hdisplay * 1000) / sr_clock;
sr_entries = (((latency_ns / line_time_us) + 1) * pixel_size *
sr_hdisplay) / 1000;
sr_entries = roundup(sr_entries / wm_params->cacheline_size, 1);
if (sr_entries < wm_params->fifo_size)
srwm = wm_params->fifo_size - sr_entries;
}
DRM_DEBUG("Setting FIFO watermarks - A: %d, B: %d, C: %d, SR %d\n",
awm, bwm, cwm, srwm);
fwater_lo = fwater_lo | ((bwm & 0x3f) << 16) | (awm & 0x3f);
fwater_hi = fwater_hi | (cwm & 0x1f);
I915_WRITE(FW_BLC, fwater_lo);
I915_WRITE(FW_BLC2, fwater_hi);
if (IS_I9XX(dev))
I915_WRITE(FW_BLC_SELF, FW_BLC_SELF_EN | (srwm & 0x3f));
}
static void i830_update_wm(struct drm_device *dev, int planea_clock,
int pixel_size)
{
struct drm_i915_private *dev_priv = dev->dev_private;
uint32_t dsparb = I915_READ(DSPARB);
uint32_t fwater_lo = I915_READ(FW_BLC) & MM_FIFO_WATERMARK;
unsigned int asize, awm;
int planea_entries;
planea_entries = intel_calculate_wm(planea_clock, &i830_wm_info,
pixel_size, latency_ns);
asize = dsparb & 0x7f;
awm = asize - planea_entries;
fwater_lo = fwater_lo | awm;
I915_WRITE(FW_BLC, fwater_lo);
}
/**
* intel_update_watermarks - update FIFO watermark values based on current modes
*
* Calculate watermark values for the various WM regs based on current mode
* and plane configuration.
*
* There are several cases to deal with here:
* - normal (i.e. non-self-refresh)
* - self-refresh (SR) mode
* - lines are large relative to FIFO size (buffer can hold up to 2)
* - lines are small relative to FIFO size (buffer can hold more than 2
* lines), so need to account for TLB latency
*
* The normal calculation is:
* watermark = dotclock * bytes per pixel * latency
* where latency is platform & configuration dependent (we assume pessimal
* values here).
*
* The SR calculation is:
* watermark = (trunc(latency/line time)+1) * surface width *
* bytes per pixel
* where
* line time = htotal / dotclock
* and latency is assumed to be high, as above.
*
* The final value programmed to the register should always be rounded up,
* and include an extra 2 entries to account for clock crossings.
*
* We don't use the sprite, so we can ignore that. And on Crestline we have
* to set the non-SR watermarks to 8.
*/
static void intel_update_watermarks(struct drm_device *dev)
{
struct drm_crtc *crtc;
struct intel_crtc *intel_crtc;
int sr_hdisplay = 0;
unsigned long planea_clock = 0, planeb_clock = 0, sr_clock = 0;
int enabled = 0, pixel_size = 0;
if (DSPARB_HWCONTROL(dev))
return;
/* Get the clock config from both planes */
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
intel_crtc = to_intel_crtc(crtc);
if (crtc->enabled) {
enabled++;
if (intel_crtc->plane == 0) {
DRM_DEBUG("plane A (pipe %d) clock: %d\n",
intel_crtc->pipe, crtc->mode.clock);
planea_clock = crtc->mode.clock;
} else {
DRM_DEBUG("plane B (pipe %d) clock: %d\n",
intel_crtc->pipe, crtc->mode.clock);
planeb_clock = crtc->mode.clock;
}
sr_hdisplay = crtc->mode.hdisplay;
sr_clock = crtc->mode.clock;
if (crtc->fb)
pixel_size = crtc->fb->bits_per_pixel / 8;
else
pixel_size = 4; /* by default */
}
}
if (enabled <= 0)
return;
/* Single pipe configs can enable self refresh */
if (enabled == 1 && IS_IGD(dev))
igd_enable_cxsr(dev, sr_clock, pixel_size);
else if (IS_IGD(dev))
igd_disable_cxsr(dev);
if (IS_I965G(dev))
i965_update_wm(dev);
else if (IS_I9XX(dev) || IS_MOBILE(dev))
i9xx_update_wm(dev, planea_clock, planeb_clock, sr_hdisplay,
pixel_size);
else
i830_update_wm(dev, planea_clock, pixel_size);
}
static int intel_crtc_mode_set(struct drm_crtc *crtc, static int intel_crtc_mode_set(struct drm_crtc *crtc,
struct drm_display_mode *mode, struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode, struct drm_display_mode *adjusted_mode,
@ -1951,6 +2365,9 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
/* Flush the plane changes */ /* Flush the plane changes */
ret = intel_pipe_set_base(crtc, x, y, old_fb); ret = intel_pipe_set_base(crtc, x, y, old_fb);
intel_update_watermarks(dev);
drm_vblank_post_modeset(dev, pipe); drm_vblank_post_modeset(dev, pipe);
return ret; return ret;
@ -2439,6 +2856,7 @@ static void intel_crtc_init(struct drm_device *dev, int pipe)
drm_mode_crtc_set_gamma_size(&intel_crtc->base, 256); drm_mode_crtc_set_gamma_size(&intel_crtc->base, 256);
intel_crtc->pipe = pipe; intel_crtc->pipe = pipe;
intel_crtc->plane = pipe;
for (i = 0; i < 256; i++) { for (i = 0; i < 256; i++) {
intel_crtc->lut_r[i] = i; intel_crtc->lut_r[i] = i;
intel_crtc->lut_g[i] = i; intel_crtc->lut_g[i] = i;

View File

@ -246,7 +246,7 @@ intel_dp_aux_ch(struct intel_output *intel_output,
} }
if ((status & DP_AUX_CH_CTL_DONE) == 0) { if ((status & DP_AUX_CH_CTL_DONE) == 0) {
printk(KERN_ERR "dp_aux_ch not done status 0x%08x\n", status); DRM_ERROR("dp_aux_ch not done status 0x%08x\n", status);
return -EBUSY; return -EBUSY;
} }
@ -254,11 +254,14 @@ intel_dp_aux_ch(struct intel_output *intel_output,
* Timeouts occur when the sink is not connected * Timeouts occur when the sink is not connected
*/ */
if (status & DP_AUX_CH_CTL_RECEIVE_ERROR) { if (status & DP_AUX_CH_CTL_RECEIVE_ERROR) {
printk(KERN_ERR "dp_aux_ch receive error status 0x%08x\n", status); DRM_ERROR("dp_aux_ch receive error status 0x%08x\n", status);
return -EIO; return -EIO;
} }
/* Timeouts occur when the device isn't connected, so they're
* "normal" -- don't fill the kernel log with these */
if (status & DP_AUX_CH_CTL_TIME_OUT_ERROR) { if (status & DP_AUX_CH_CTL_TIME_OUT_ERROR) {
printk(KERN_ERR "dp_aux_ch timeout status 0x%08x\n", status); DRM_DEBUG("dp_aux_ch timeout status 0x%08x\n", status);
return -ETIMEDOUT; return -ETIMEDOUT;
} }
@ -411,7 +414,7 @@ intel_dp_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode,
dp_priv->link_bw = bws[clock]; dp_priv->link_bw = bws[clock];
dp_priv->lane_count = lane_count; dp_priv->lane_count = lane_count;
adjusted_mode->clock = intel_dp_link_clock(dp_priv->link_bw); adjusted_mode->clock = intel_dp_link_clock(dp_priv->link_bw);
printk(KERN_ERR "link bw %02x lane count %d clock %d\n", DRM_DEBUG("Display port link bw %02x lane count %d clock %d\n",
dp_priv->link_bw, dp_priv->lane_count, dp_priv->link_bw, dp_priv->lane_count,
adjusted_mode->clock); adjusted_mode->clock);
return true; return true;

View File

@ -29,6 +29,7 @@
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include "intel_dp.h" #include "intel_dp.h"
#include "drmP.h"
/* Run a single AUX_CH I2C transaction, writing/reading data as necessary */ /* Run a single AUX_CH I2C transaction, writing/reading data as necessary */
@ -84,7 +85,7 @@ i2c_algo_dp_aux_transaction(struct i2c_adapter *adapter, int mode,
msg, msg_bytes, msg, msg_bytes,
reply, reply_bytes); reply, reply_bytes);
if (ret < 0) { if (ret < 0) {
printk(KERN_ERR "aux_ch failed %d\n", ret); DRM_DEBUG("aux_ch failed %d\n", ret);
return ret; return ret;
} }
switch (reply[0] & AUX_I2C_REPLY_MASK) { switch (reply[0] & AUX_I2C_REPLY_MASK) {
@ -94,14 +95,14 @@ i2c_algo_dp_aux_transaction(struct i2c_adapter *adapter, int mode,
} }
return reply_bytes - 1; return reply_bytes - 1;
case AUX_I2C_REPLY_NACK: case AUX_I2C_REPLY_NACK:
printk(KERN_ERR "aux_ch nack\n"); DRM_DEBUG("aux_ch nack\n");
return -EREMOTEIO; return -EREMOTEIO;
case AUX_I2C_REPLY_DEFER: case AUX_I2C_REPLY_DEFER:
printk(KERN_ERR "aux_ch defer\n"); DRM_DEBUG("aux_ch defer\n");
udelay(100); udelay(100);
break; break;
default: default:
printk(KERN_ERR "aux_ch invalid reply 0x%02x\n", reply[0]); DRM_ERROR("aux_ch invalid reply 0x%02x\n", reply[0]);
return -EREMOTEIO; return -EREMOTEIO;
} }
} }
@ -223,7 +224,7 @@ i2c_algo_dp_aux_xfer(struct i2c_adapter *adapter,
if (ret >= 0) if (ret >= 0)
ret = num; ret = num;
i2c_algo_dp_aux_stop(adapter, reading); i2c_algo_dp_aux_stop(adapter, reading);
printk(KERN_ERR "dp_aux_xfer return %d\n", ret); DRM_DEBUG("dp_aux_xfer return %d\n", ret);
return ret; return ret;
} }

View File

@ -453,7 +453,7 @@ static int intelfb_create(struct drm_device *dev, uint32_t fb_width,
size = ALIGN(size, PAGE_SIZE); size = ALIGN(size, PAGE_SIZE);
fbo = drm_gem_object_alloc(dev, size); fbo = drm_gem_object_alloc(dev, size);
if (!fbo) { if (!fbo) {
printk(KERN_ERR "failed to allocate framebuffer\n"); DRM_ERROR("failed to allocate framebuffer\n");
ret = -ENOMEM; ret = -ENOMEM;
goto out; goto out;
} }
@ -610,8 +610,8 @@ static int intelfb_create(struct drm_device *dev, uint32_t fb_width,
par->dev = dev; par->dev = dev;
/* To allow resizeing without swapping buffers */ /* To allow resizeing without swapping buffers */
printk("allocated %dx%d fb: 0x%08x, bo %p\n", intel_fb->base.width, DRM_DEBUG("allocated %dx%d fb: 0x%08x, bo %p\n", intel_fb->base.width,
intel_fb->base.height, obj_priv->gtt_offset, fbo); intel_fb->base.height, obj_priv->gtt_offset, fbo);
mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->struct_mutex);
return 0; return 0;
@ -698,13 +698,13 @@ static int intelfb_multi_fb_probe_crtc(struct drm_device *dev, struct drm_crtc *
} else } else
intelfb_set_par(info); intelfb_set_par(info);
printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node, DRM_INFO("fb%d: %s frame buffer device\n", info->node,
info->fix.id); info->fix.id);
/* Switch back to kernel console on panic */ /* Switch back to kernel console on panic */
kernelfb_mode = *modeset; kernelfb_mode = *modeset;
atomic_notifier_chain_register(&panic_notifier_list, &paniced); atomic_notifier_chain_register(&panic_notifier_list, &paniced);
printk(KERN_INFO "registered panic notifier\n"); DRM_DEBUG("registered panic notifier\n");
return 0; return 0;
} }
@ -852,13 +852,13 @@ static int intelfb_single_fb_probe(struct drm_device *dev)
} else } else
intelfb_set_par(info); intelfb_set_par(info);
printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node, DRM_INFO("fb%d: %s frame buffer device\n", info->node,
info->fix.id); info->fix.id);
/* Switch back to kernel console on panic */ /* Switch back to kernel console on panic */
kernelfb_mode = *modeset; kernelfb_mode = *modeset;
atomic_notifier_chain_register(&panic_notifier_list, &paniced); atomic_notifier_chain_register(&panic_notifier_list, &paniced);
printk(KERN_INFO "registered panic notifier\n"); DRM_DEBUG("registered panic notifier\n");
return 0; return 0;
} }
@ -872,8 +872,8 @@ void intelfb_restore(void)
{ {
int ret; int ret;
if ((ret = drm_crtc_helper_set_config(&kernelfb_mode)) != 0) { if ((ret = drm_crtc_helper_set_config(&kernelfb_mode)) != 0) {
printk(KERN_ERR "Failed to restore crtc configuration: %d\n", DRM_ERROR("Failed to restore crtc configuration: %d\n",
ret); ret);
} }
} }

View File

@ -36,6 +36,7 @@
#include "intel_drv.h" #include "intel_drv.h"
#include "i915_drm.h" #include "i915_drm.h"
#include "i915_drv.h" #include "i915_drv.h"
#include <linux/acpi.h>
#define I915_LVDS "i915_lvds" #define I915_LVDS "i915_lvds"
@ -252,14 +253,14 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder,
/* Should never happen!! */ /* Should never happen!! */
if (!IS_I965G(dev) && intel_crtc->pipe == 0) { if (!IS_I965G(dev) && intel_crtc->pipe == 0) {
printk(KERN_ERR "Can't support LVDS on pipe A\n"); DRM_ERROR("Can't support LVDS on pipe A\n");
return false; return false;
} }
/* Should never happen!! */ /* Should never happen!! */
list_for_each_entry(tmp_encoder, &dev->mode_config.encoder_list, head) { list_for_each_entry(tmp_encoder, &dev->mode_config.encoder_list, head) {
if (tmp_encoder != encoder && tmp_encoder->crtc == encoder->crtc) { if (tmp_encoder != encoder && tmp_encoder->crtc == encoder->crtc) {
printk(KERN_ERR "Can't enable LVDS and another " DRM_ERROR("Can't enable LVDS and another "
"encoder on the same pipe\n"); "encoder on the same pipe\n");
return false; return false;
} }
@ -788,6 +789,65 @@ static const struct dmi_system_id intel_no_lvds[] = {
{ } /* terminating entry */ { } /* terminating entry */
}; };
#ifdef CONFIG_ACPI
/*
* check_lid_device -- check whether @handle is an ACPI LID device.
* @handle: ACPI device handle
* @level : depth in the ACPI namespace tree
* @context: the number of LID device when we find the device
* @rv: a return value to fill if desired (Not use)
*/
static acpi_status
check_lid_device(acpi_handle handle, u32 level, void *context,
void **return_value)
{
struct acpi_device *acpi_dev;
int *lid_present = context;
acpi_dev = NULL;
/* Get the acpi device for device handle */
if (acpi_bus_get_device(handle, &acpi_dev) || !acpi_dev) {
/* If there is no ACPI device for handle, return */
return AE_OK;
}
if (!strncmp(acpi_device_hid(acpi_dev), "PNP0C0D", 7))
*lid_present = 1;
return AE_OK;
}
/**
* check whether there exists the ACPI LID device by enumerating the ACPI
* device tree.
*/
static int intel_lid_present(void)
{
int lid_present = 0;
if (acpi_disabled) {
/* If ACPI is disabled, there is no ACPI device tree to
* check, so assume the LID device would have been present.
*/
return 1;
}
acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
ACPI_UINT32_MAX,
check_lid_device, &lid_present, NULL);
return lid_present;
}
#else
static int intel_lid_present(void)
{
/* In the absence of ACPI built in, assume that the LID device would
* have been present.
*/
return 1;
}
#endif
/** /**
* intel_lvds_init - setup LVDS connectors on this device * intel_lvds_init - setup LVDS connectors on this device
* @dev: drm device * @dev: drm device
@ -811,6 +871,16 @@ void intel_lvds_init(struct drm_device *dev)
if (dmi_check_system(intel_no_lvds)) if (dmi_check_system(intel_no_lvds))
return; return;
/* Assume that any device without an ACPI LID device also doesn't
* have an integrated LVDS. We would be better off parsing the BIOS
* to get a reliable indicator, but that code isn't written yet.
*
* In the case of all-in-one desktops using LVDS that we've seen,
* they're using SDVO LVDS.
*/
if (!intel_lid_present())
return;
if (IS_IGDNG(dev)) { if (IS_IGDNG(dev)) {
if ((I915_READ(PCH_LVDS) & LVDS_DETECTED) == 0) if ((I915_READ(PCH_LVDS) & LVDS_DETECTED) == 0)
return; return;

View File

@ -68,11 +68,22 @@ struct intel_sdvo_priv {
* This is set if we treat the device as HDMI, instead of DVI. * This is set if we treat the device as HDMI, instead of DVI.
*/ */
bool is_hdmi; bool is_hdmi;
/** /**
* This is set if we detect output of sdvo device as LVDS. * This is set if we detect output of sdvo device as LVDS.
*/ */
bool is_lvds; bool is_lvds;
/**
* This is sdvo flags for input timing.
*/
uint8_t sdvo_flags;
/**
* This is sdvo fixed pannel mode pointer
*/
struct drm_display_mode *sdvo_lvds_fixed_mode;
/** /**
* Returned SDTV resolutions allowed for the current format, if the * Returned SDTV resolutions allowed for the current format, if the
* device reported it. * device reported it.
@ -592,6 +603,7 @@ intel_sdvo_create_preferred_input_timing(struct intel_output *output,
uint16_t height) uint16_t height)
{ {
struct intel_sdvo_preferred_input_timing_args args; struct intel_sdvo_preferred_input_timing_args args;
struct intel_sdvo_priv *sdvo_priv = output->dev_priv;
uint8_t status; uint8_t status;
memset(&args, 0, sizeof(args)); memset(&args, 0, sizeof(args));
@ -599,7 +611,12 @@ intel_sdvo_create_preferred_input_timing(struct intel_output *output,
args.width = width; args.width = width;
args.height = height; args.height = height;
args.interlace = 0; args.interlace = 0;
args.scaled = 0;
if (sdvo_priv->is_lvds &&
(sdvo_priv->sdvo_lvds_fixed_mode->hdisplay != width ||
sdvo_priv->sdvo_lvds_fixed_mode->vdisplay != height))
args.scaled = 1;
intel_sdvo_write_cmd(output, SDVO_CMD_CREATE_PREFERRED_INPUT_TIMING, intel_sdvo_write_cmd(output, SDVO_CMD_CREATE_PREFERRED_INPUT_TIMING,
&args, sizeof(args)); &args, sizeof(args));
status = intel_sdvo_read_response(output, NULL, 0); status = intel_sdvo_read_response(output, NULL, 0);
@ -944,12 +961,7 @@ static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder,
struct intel_output *output = enc_to_intel_output(encoder); struct intel_output *output = enc_to_intel_output(encoder);
struct intel_sdvo_priv *dev_priv = output->dev_priv; struct intel_sdvo_priv *dev_priv = output->dev_priv;
if (!dev_priv->is_tv) { if (dev_priv->is_tv) {
/* Make the CRTC code factor in the SDVO pixel multiplier. The
* SDVO device will be told of the multiplier during mode_set.
*/
adjusted_mode->clock *= intel_sdvo_get_pixel_multiplier(mode);
} else {
struct intel_sdvo_dtd output_dtd; struct intel_sdvo_dtd output_dtd;
bool success; bool success;
@ -980,6 +992,7 @@ static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder,
intel_sdvo_get_preferred_input_timing(output, intel_sdvo_get_preferred_input_timing(output,
&input_dtd); &input_dtd);
intel_sdvo_get_mode_from_dtd(adjusted_mode, &input_dtd); intel_sdvo_get_mode_from_dtd(adjusted_mode, &input_dtd);
dev_priv->sdvo_flags = input_dtd.part2.sdvo_flags;
drm_mode_set_crtcinfo(adjusted_mode, 0); drm_mode_set_crtcinfo(adjusted_mode, 0);
@ -990,6 +1003,52 @@ static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder,
} else { } else {
return false; return false;
} }
} else if (dev_priv->is_lvds) {
struct intel_sdvo_dtd output_dtd;
bool success;
drm_mode_set_crtcinfo(dev_priv->sdvo_lvds_fixed_mode, 0);
/* Set output timings */
intel_sdvo_get_dtd_from_mode(&output_dtd,
dev_priv->sdvo_lvds_fixed_mode);
intel_sdvo_set_target_output(output,
dev_priv->controlled_output);
intel_sdvo_set_output_timing(output, &output_dtd);
/* Set the input timing to the screen. Assume always input 0. */
intel_sdvo_set_target_input(output, true, false);
success = intel_sdvo_create_preferred_input_timing(
output,
mode->clock / 10,
mode->hdisplay,
mode->vdisplay);
if (success) {
struct intel_sdvo_dtd input_dtd;
intel_sdvo_get_preferred_input_timing(output,
&input_dtd);
intel_sdvo_get_mode_from_dtd(adjusted_mode, &input_dtd);
dev_priv->sdvo_flags = input_dtd.part2.sdvo_flags;
drm_mode_set_crtcinfo(adjusted_mode, 0);
mode->clock = adjusted_mode->clock;
adjusted_mode->clock *=
intel_sdvo_get_pixel_multiplier(mode);
} else {
return false;
}
} else {
/* Make the CRTC code factor in the SDVO pixel multiplier. The
* SDVO device will be told of the multiplier during mode_set.
*/
adjusted_mode->clock *= intel_sdvo_get_pixel_multiplier(mode);
} }
return true; return true;
} }
@ -1033,15 +1092,16 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder,
/* We have tried to get input timing in mode_fixup, and filled into /* We have tried to get input timing in mode_fixup, and filled into
adjusted_mode */ adjusted_mode */
if (sdvo_priv->is_tv) if (sdvo_priv->is_tv || sdvo_priv->is_lvds) {
intel_sdvo_get_dtd_from_mode(&input_dtd, adjusted_mode); intel_sdvo_get_dtd_from_mode(&input_dtd, adjusted_mode);
else input_dtd.part2.sdvo_flags = sdvo_priv->sdvo_flags;
} else
intel_sdvo_get_dtd_from_mode(&input_dtd, mode); intel_sdvo_get_dtd_from_mode(&input_dtd, mode);
/* If it's a TV, we already set the output timing in mode_fixup. /* If it's a TV, we already set the output timing in mode_fixup.
* Otherwise, the output timing is equal to the input timing. * Otherwise, the output timing is equal to the input timing.
*/ */
if (!sdvo_priv->is_tv) { if (!sdvo_priv->is_tv && !sdvo_priv->is_lvds) {
/* Set the output timing to the screen */ /* Set the output timing to the screen */
intel_sdvo_set_target_output(output, intel_sdvo_set_target_output(output,
sdvo_priv->controlled_output); sdvo_priv->controlled_output);
@ -1116,6 +1176,8 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder,
sdvox |= (sdvo_pixel_multiply - 1) << SDVO_PORT_MULTIPLY_SHIFT; sdvox |= (sdvo_pixel_multiply - 1) << SDVO_PORT_MULTIPLY_SHIFT;
} }
if (sdvo_priv->sdvo_flags & SDVO_NEED_TO_STALL)
sdvox |= SDVO_STALL_SELECT;
intel_sdvo_write_sdvox(output, sdvox); intel_sdvo_write_sdvox(output, sdvox);
} }
@ -1276,6 +1338,17 @@ static int intel_sdvo_mode_valid(struct drm_connector *connector,
if (sdvo_priv->pixel_clock_max < mode->clock) if (sdvo_priv->pixel_clock_max < mode->clock)
return MODE_CLOCK_HIGH; return MODE_CLOCK_HIGH;
if (sdvo_priv->is_lvds == true) {
if (sdvo_priv->sdvo_lvds_fixed_mode == NULL)
return MODE_PANEL;
if (mode->hdisplay > sdvo_priv->sdvo_lvds_fixed_mode->hdisplay)
return MODE_PANEL;
if (mode->vdisplay > sdvo_priv->sdvo_lvds_fixed_mode->vdisplay)
return MODE_PANEL;
}
return MODE_OK; return MODE_OK;
} }
@ -1549,6 +1622,8 @@ static void intel_sdvo_get_lvds_modes(struct drm_connector *connector)
{ {
struct intel_output *intel_output = to_intel_output(connector); struct intel_output *intel_output = to_intel_output(connector);
struct drm_i915_private *dev_priv = connector->dev->dev_private; struct drm_i915_private *dev_priv = connector->dev->dev_private;
struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
struct drm_display_mode *newmode;
/* /*
* Attempt to get the mode list from DDC. * Attempt to get the mode list from DDC.
@ -1557,11 +1632,10 @@ static void intel_sdvo_get_lvds_modes(struct drm_connector *connector)
*/ */
intel_ddc_get_modes(intel_output); intel_ddc_get_modes(intel_output);
if (list_empty(&connector->probed_modes) == false) if (list_empty(&connector->probed_modes) == false)
return; goto end;
/* Fetch modes from VBT */ /* Fetch modes from VBT */
if (dev_priv->sdvo_lvds_vbt_mode != NULL) { if (dev_priv->sdvo_lvds_vbt_mode != NULL) {
struct drm_display_mode *newmode;
newmode = drm_mode_duplicate(connector->dev, newmode = drm_mode_duplicate(connector->dev,
dev_priv->sdvo_lvds_vbt_mode); dev_priv->sdvo_lvds_vbt_mode);
if (newmode != NULL) { if (newmode != NULL) {
@ -1571,6 +1645,16 @@ static void intel_sdvo_get_lvds_modes(struct drm_connector *connector)
drm_mode_probed_add(connector, newmode); drm_mode_probed_add(connector, newmode);
} }
} }
end:
list_for_each_entry(newmode, &connector->probed_modes, head) {
if (newmode->type & DRM_MODE_TYPE_PREFERRED) {
sdvo_priv->sdvo_lvds_fixed_mode =
drm_mode_duplicate(connector->dev, newmode);
break;
}
}
} }
static int intel_sdvo_get_modes(struct drm_connector *connector) static int intel_sdvo_get_modes(struct drm_connector *connector)
@ -1593,14 +1677,20 @@ static int intel_sdvo_get_modes(struct drm_connector *connector)
static void intel_sdvo_destroy(struct drm_connector *connector) static void intel_sdvo_destroy(struct drm_connector *connector)
{ {
struct intel_output *intel_output = to_intel_output(connector); struct intel_output *intel_output = to_intel_output(connector);
struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
if (intel_output->i2c_bus) if (intel_output->i2c_bus)
intel_i2c_destroy(intel_output->i2c_bus); intel_i2c_destroy(intel_output->i2c_bus);
if (intel_output->ddc_bus) if (intel_output->ddc_bus)
intel_i2c_destroy(intel_output->ddc_bus); intel_i2c_destroy(intel_output->ddc_bus);
if (sdvo_priv->sdvo_lvds_fixed_mode != NULL)
drm_mode_destroy(connector->dev,
sdvo_priv->sdvo_lvds_fixed_mode);
drm_sysfs_connector_remove(connector); drm_sysfs_connector_remove(connector);
drm_connector_cleanup(connector); drm_connector_cleanup(connector);
kfree(intel_output); kfree(intel_output);
} }

View File

@ -715,6 +715,7 @@ struct intel_sdvo_enhancements_arg {
#define SDVO_HBUF_TX_ONCE (2 << 6) #define SDVO_HBUF_TX_ONCE (2 << 6)
#define SDVO_HBUF_TX_VSYNC (3 << 6) #define SDVO_HBUF_TX_VSYNC (3 << 6)
#define SDVO_CMD_GET_AUDIO_TX_INFO 0x9c #define SDVO_CMD_GET_AUDIO_TX_INFO 0x9c
#define SDVO_NEED_TO_STALL (1 << 7)
struct intel_sdvo_encode{ struct intel_sdvo_encode{
u8 dvi_rev; u8 dvi_rev;