Commit bb8ad281 authored by Linus Torvalds's avatar Linus Torvalds

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
  ...
parents c368b492 5019914c
...@@ -1090,6 +1090,8 @@ int drm_helper_resume_force_mode(struct drm_device *dev) ...@@ -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);
...@@ -846,7 +846,7 @@ static int i915_set_status_page(struct drm_device *dev, void *data, ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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;
......
...@@ -35,6 +35,7 @@ ...@@ -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) ...@@ -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) ...@@ -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;
} }
......
...@@ -133,6 +133,22 @@ struct sdvo_device_mapping { ...@@ -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 { ...@@ -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 { ...@@ -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); ...@@ -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); ...@@ -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)
......
...@@ -1252,6 +1252,31 @@ i915_gem_create_mmap_offset(struct drm_gem_object *obj) ...@@ -1252,6 +1252,31 @@ i915_gem_create_mmap_offset(struct drm_gem_object *obj)
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) ...@@ -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) ...@@ -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 @@ i915_gem_object_get_fence_reg(struct drm_gem_object *obj) ...@@ -2222,7 +2244,6 @@ i915_gem_object_get_fence_reg(struct drm_gem_object *obj)
/* 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 @@ i915_gem_object_get_fence_reg(struct drm_gem_object *obj) ...@@ -2274,10 +2295,7 @@ i915_gem_object_get_fence_reg(struct drm_gem_object *obj)
* 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;
} }
......
...@@ -75,11 +75,10 @@ static int i915_gem_object_list_info(struct seq_file *m, void *data) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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[] = { ...@@ -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)
......
...@@ -521,6 +521,12 @@ i915_gem_set_tiling(struct drm_device *dev, void *data, ...@@ -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;
} }
......
...@@ -26,6 +26,7 @@ ...@@ -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 @@ ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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);
......
...@@ -206,6 +206,7 @@ ...@@ -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 @@ ...@@ -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 @@ ...@@ -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 @@ ...@@ -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 @@ ...@@ -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
......
...@@ -222,23 +222,12 @@ static void i915_restore_vga(struct drm_device *dev) ...@@ -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) ...@@ -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) ...@@ -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);
......
...@@ -97,6 +97,7 @@ static void ...@@ -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, ...@@ -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, ...@@ -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;
} }
} }
} }
......
...@@ -46,7 +46,7 @@ static void intel_crt_dpms(struct drm_encoder *encoder, int mode) ...@@ -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) ...@@ -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,
......
This diff is collapsed.
...@@ -246,7 +246,7 @@ intel_dp_aux_ch(struct intel_output *intel_output, ...@@ -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, ...@@ -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, ...@@ -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;
......
...@@ -29,6 +29,7 @@ ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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;
} }
......
...@@ -453,7 +453,7 @@ static int intelfb_create(struct drm_device *dev, uint32_t fb_width, ...@@ -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, ...@@ -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 * ...@@ -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) ...@@ -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) ...@@ -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);
} }
} }
......
...@@ -36,6 +36,7 @@ ...@@ -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, ...@@ -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[] = { ...@@ -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) ...@@ -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;
......
...@@ -68,11 +68,22 @@ struct intel_sdvo_priv { ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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,47 @@ static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder, ...@@ -980,6 +992,47 @@ 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);
mode->clock = adjusted_mode->clock;
adjusted_mode->clock *=
intel_sdvo_get_pixel_multiplier(mode);
} else {
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); drm_mode_set_crtcinfo(adjusted_mode, 0);
...@@ -990,6 +1043,12 @@ static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder, ...@@ -990,6 +1043,12 @@ static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder,
} else { } else {
return false; 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, ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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);
} }
......
...@@ -715,6 +715,7 @@ struct intel_sdvo_enhancements_arg { ...@@ -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;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment