forked from Minki/linux
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:
commit
bb8ad2815a
@ -1090,6 +1090,8 @@ int drm_helper_resume_force_mode(struct drm_device *dev)
|
||||
if (ret == false)
|
||||
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;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_helper_resume_force_mode);
|
||||
|
@ -846,7 +846,7 @@ static int i915_set_status_page(struct drm_device *dev, void *data,
|
||||
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);
|
||||
|
||||
@ -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
|
||||
* 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,
|
||||
unsigned long *preallocated_size)
|
||||
static int i915_probe_agp(struct drm_device *dev, uint32_t *aperture_size,
|
||||
uint32_t *preallocated_size)
|
||||
{
|
||||
struct pci_dev *bridge_dev;
|
||||
u16 tmp = 0;
|
||||
@ -984,10 +984,11 @@ static int i915_probe_agp(struct drm_device *dev, unsigned long *aperture_size,
|
||||
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;
|
||||
unsigned long agp_size, prealloc_size;
|
||||
int fb_bar = IS_I9XX(dev) ? 2 : 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))
|
||||
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) */
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
||||
* @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;
|
||||
resource_size_t base, size;
|
||||
int ret = 0, mmio_bar = IS_I9XX(dev) ? 0 : 1;
|
||||
uint32_t agp_size, prealloc_size;
|
||||
|
||||
/* i915 has 4 more counters */
|
||||
dev->counters += 4;
|
||||
@ -1146,9 +1182,22 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
|
||||
"performance may suffer.\n");
|
||||
}
|
||||
|
||||
ret = i915_probe_agp(dev, &agp_size, &prealloc_size);
|
||||
if (ret)
|
||||
goto out_iomapfree;
|
||||
|
||||
/* enable GEM by default */
|
||||
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->max_vblank_count = 0xffffff; /* only 24 bits of frame count */
|
||||
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;
|
||||
}
|
||||
|
||||
i915_get_mem_freq(dev);
|
||||
|
||||
/* On the 945G/GM, the chipset reports the MSI capability on the
|
||||
* integrated graphics even though the support isn't actually there
|
||||
* 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);
|
||||
|
||||
spin_lock_init(&dev_priv->user_irq_lock);
|
||||
spin_lock_init(&dev_priv->error_lock);
|
||||
dev_priv->user_irq_refcount = 0;
|
||||
|
||||
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)) {
|
||||
ret = i915_load_modeset_init(dev);
|
||||
ret = i915_load_modeset_init(dev, prealloc_size, agp_size);
|
||||
if (ret < 0) {
|
||||
DRM_ERROR("failed to init modeset\n");
|
||||
goto out_rmmap;
|
||||
|
@ -35,6 +35,7 @@
|
||||
|
||||
#include "drm_pciids.h"
|
||||
#include <linux/console.h>
|
||||
#include "drm_crtc_helper.h"
|
||||
|
||||
static unsigned int i915_modeset = -1;
|
||||
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;
|
||||
|
||||
if (!dev || !dev_priv) {
|
||||
printk(KERN_ERR "dev: %p, dev_priv: %p\n", dev, dev_priv);
|
||||
printk(KERN_ERR "DRM not initialized, aborting suspend.\n");
|
||||
DRM_ERROR("dev: %p, dev_priv: %p\n", dev, dev_priv);
|
||||
DRM_ERROR("DRM not initialized, aborting suspend.\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
@ -115,6 +116,10 @@ static int i915_resume(struct drm_device *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;
|
||||
}
|
||||
|
@ -133,6 +133,22 @@ struct sdvo_device_mapping {
|
||||
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 {
|
||||
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 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 */
|
||||
u8 saveLBB;
|
||||
u32 saveDSPACNTR;
|
||||
@ -468,9 +489,6 @@ struct drm_i915_gem_object {
|
||||
*/
|
||||
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 */
|
||||
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);
|
||||
void i915_gem_object_unpin(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);
|
||||
uint32_t i915_get_gem_seqno(struct drm_device *dev);
|
||||
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_DP(dev) (IS_G4X(dev) || IS_IGDNG(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)
|
||||
|
||||
|
@ -1252,6 +1252,31 @@ out_free_list:
|
||||
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
|
||||
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_i915_gem_object *obj_priv = obj->driver_private;
|
||||
loff_t offset;
|
||||
int ret = 0;
|
||||
|
||||
#if WATCH_BUF
|
||||
@ -1898,9 +1922,7 @@ i915_gem_object_unbind(struct drm_gem_object *obj)
|
||||
BUG_ON(obj_priv->active);
|
||||
|
||||
/* blow away mappings if mapped through GTT */
|
||||
offset = ((loff_t) obj->map_list.hash.key) << PAGE_SHIFT;
|
||||
if (dev->dev_mapping)
|
||||
unmap_mapping_range(dev->dev_mapping, offset, obj->size, 1);
|
||||
i915_gem_release_mmap(obj);
|
||||
|
||||
if (obj_priv->fence_reg != I915_FENCE_REG_NONE)
|
||||
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 */
|
||||
if (i == dev_priv->num_fence_regs) {
|
||||
uint32_t seqno = dev_priv->mm.next_gem_seqno;
|
||||
loff_t offset;
|
||||
|
||||
if (avail == 0)
|
||||
return -ENOSPC;
|
||||
@ -2274,10 +2295,7 @@ try_again:
|
||||
* Zap this virtual mapping so we can set up a fence again
|
||||
* for this object next time we need it.
|
||||
*/
|
||||
offset = ((loff_t) reg->obj->map_list.hash.key) << PAGE_SHIFT;
|
||||
if (dev->dev_mapping)
|
||||
unmap_mapping_range(dev->dev_mapping, offset,
|
||||
reg->obj->size, 1);
|
||||
i915_gem_release_mmap(reg->obj);
|
||||
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)
|
||||
case ACTIVE_LIST:
|
||||
seq_printf(m, "Active:\n");
|
||||
lock = &dev_priv->mm.active_list_lock;
|
||||
spin_lock(lock);
|
||||
head = &dev_priv->mm.active_list;
|
||||
break;
|
||||
case INACTIVE_LIST:
|
||||
seq_printf(m, "Inctive:\n");
|
||||
seq_printf(m, "Inactive:\n");
|
||||
head = &dev_priv->mm.inactive_list;
|
||||
break;
|
||||
case FLUSHING_LIST:
|
||||
@ -91,6 +90,8 @@ static int i915_gem_object_list_info(struct seq_file *m, void *data)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lock)
|
||||
spin_lock(lock);
|
||||
list_for_each_entry(obj_priv, head, list)
|
||||
{
|
||||
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)
|
||||
seq_printf(m, " (name: %d)", obj->name);
|
||||
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");
|
||||
}
|
||||
|
||||
@ -323,6 +327,39 @@ static int i915_ringbuffer_info(struct seq_file *m, void *data)
|
||||
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[] = {
|
||||
{"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_info", i915_ringbuffer_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)
|
||||
|
||||
|
@ -521,6 +521,12 @@ i915_gem_set_tiling(struct drm_device *dev, void *data,
|
||||
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->stride = args->stride;
|
||||
}
|
||||
|
@ -26,6 +26,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/sysrq.h>
|
||||
#include "drmP.h"
|
||||
#include "drm.h"
|
||||
#include "i915_drm.h"
|
||||
@ -41,9 +42,10 @@
|
||||
* we leave them always unmasked in IMR and then control enabling them through
|
||||
* PIPESTAT alone.
|
||||
*/
|
||||
#define I915_INTERRUPT_ENABLE_FIX (I915_ASLE_INTERRUPT | \
|
||||
I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | \
|
||||
I915_DISPLAY_PIPE_B_EVENT_INTERRUPT)
|
||||
#define I915_INTERRUPT_ENABLE_FIX (I915_ASLE_INTERRUPT | \
|
||||
I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | \
|
||||
I915_DISPLAY_PIPE_B_EVENT_INTERRUPT | \
|
||||
I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT)
|
||||
|
||||
/** Interrupts that we mask and unmask at runtime. */
|
||||
#define I915_INTERRUPT_ENABLE_VAR (I915_USER_INTERRUPT)
|
||||
@ -288,6 +290,47 @@ irqreturn_t igdng_irq_handler(struct drm_device *dev)
|
||||
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)
|
||||
{
|
||||
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
|
||||
*/
|
||||
if (pipea_stats & 0x8000ffff) {
|
||||
if (pipea_stats & PIPE_FIFO_UNDERRUN_STATUS)
|
||||
DRM_DEBUG("pipe a underrun\n");
|
||||
I915_WRITE(PIPEASTAT, pipea_stats);
|
||||
irq_received = 1;
|
||||
}
|
||||
|
||||
if (pipeb_stats & 0x8000ffff) {
|
||||
if (pipeb_stats & PIPE_FIFO_UNDERRUN_STATUS)
|
||||
DRM_DEBUG("pipe b underrun\n");
|
||||
I915_WRITE(PIPEBSTAT, pipeb_stats);
|
||||
irq_received = 1;
|
||||
}
|
||||
@ -362,6 +409,80 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
|
||||
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);
|
||||
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;
|
||||
u32 enable_mask = I915_INTERRUPT_ENABLE_FIX | I915_INTERRUPT_ENABLE_VAR;
|
||||
u32 error_mask;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 */
|
||||
I915_WRITE(PIPEASTAT, I915_READ(PIPEASTAT) & 0x8000ffff);
|
||||
I915_WRITE(PIPEBSTAT, I915_READ(PIPEBSTAT) & 0x8000ffff);
|
||||
|
@ -206,6 +206,7 @@
|
||||
/*
|
||||
* Instruction and interrupt control regs
|
||||
*/
|
||||
#define PGTBL_ER 0x02024
|
||||
#define PRB0_TAIL 0x02030
|
||||
#define PRB0_HEAD 0x02034
|
||||
#define PRB0_START 0x02038
|
||||
@ -226,11 +227,18 @@
|
||||
#define PRB1_HEAD 0x02044 /* 915+ only */
|
||||
#define PRB1_START 0x02048 /* 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 HWS_PGA 0x02080
|
||||
#define HWS_ADDRESS_MASK 0xfffff000
|
||||
#define HWS_START_ADDRESS_SHIFT 4
|
||||
#define IPEIR 0x02088
|
||||
#define IPEHR 0x0208c
|
||||
#define INSTDONE 0x02090
|
||||
#define NOPID 0x02094
|
||||
#define HWSTAM 0x02098
|
||||
#define SCPD0 0x0209c /* 915+ only */
|
||||
@ -258,10 +266,22 @@
|
||||
#define EIR 0x020b0
|
||||
#define EMR 0x020b4
|
||||
#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 ACTHD 0x020c8
|
||||
#define FW_BLC 0x020d8
|
||||
#define FW_BLC2 0x020dc
|
||||
#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 CACHE_MODE_0 0x02120 /* 915+ only */
|
||||
#define CM0_MASK_SHIFT 16
|
||||
@ -571,17 +591,21 @@
|
||||
|
||||
/* Clocking configuration register */
|
||||
#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_667 (3 << 0) /* hrawclk 166 */
|
||||
#define CLKCFG_FSB_800 (2 << 0) /* hrawclk 200 */
|
||||
#define CLKCFG_FSB_1067 (6 << 0) /* hrawclk 266 */
|
||||
#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_ALT (5 << 0) /* hrawclk 400 */
|
||||
#define CLKCFG_FSB_1600_ALT (0 << 0) /* hrawclk 400 */
|
||||
#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 */
|
||||
#define MCHBAR_RENDER_STANDBY 0x111B8
|
||||
|
||||
@ -1581,6 +1605,34 @@
|
||||
#define DSPARB_CSTART_SHIFT 7
|
||||
#define DSPARB_BSTART_MASK (0x7f)
|
||||
#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
|
||||
* reading a stable value is somewhat tricky. The following code
|
||||
|
@ -222,23 +222,12 @@ static void i915_restore_vga(struct drm_device *dev)
|
||||
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;
|
||||
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 */
|
||||
dev_priv->savePIPEACONF = I915_READ(PIPEACONF);
|
||||
dev_priv->savePIPEASRC = I915_READ(PIPEASRC);
|
||||
@ -294,7 +283,122 @@ int i915_save_state(struct drm_device *dev)
|
||||
}
|
||||
i915_save_palette(dev, PIPE_B);
|
||||
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 */
|
||||
dev_priv->saveCURACNTR = I915_READ(CURACNTR);
|
||||
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(PIPEB_DP_LINK_N, dev_priv->savePIPEB_DP_LINK_N);
|
||||
}
|
||||
|
||||
/* 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));
|
||||
|
||||
/* This is only meaningful in non-KMS mode */
|
||||
/* Don't restore them in KMS mode */
|
||||
i915_restore_modeset_reg(dev);
|
||||
/* Cursor state */
|
||||
I915_WRITE(CURAPOS, dev_priv->saveCURAPOS);
|
||||
I915_WRITE(CURACNTR, dev_priv->saveCURACNTR);
|
||||
|
@ -97,6 +97,7 @@ static void
|
||||
parse_lfp_panel_data(struct drm_i915_private *dev_priv,
|
||||
struct bdb_header *bdb)
|
||||
{
|
||||
struct drm_device *dev = dev_priv->dev;
|
||||
struct bdb_lvds_options *lvds_options;
|
||||
struct bdb_lvds_lfp_data *lvds_lfp_data;
|
||||
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 *)
|
||||
((uint8_t *)lvds_lfp_data->data + (lfp_data_size *
|
||||
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);
|
||||
|
||||
@ -195,10 +203,12 @@ parse_general_features(struct drm_i915_private *dev_priv,
|
||||
dev_priv->lvds_use_ssc = general->enable_ssc;
|
||||
|
||||
if (dev_priv->lvds_use_ssc) {
|
||||
if (IS_I855(dev_priv->dev))
|
||||
dev_priv->lvds_ssc_freq = general->ssc_freq ? 66 : 48;
|
||||
else
|
||||
dev_priv->lvds_ssc_freq = general->ssc_freq ? 100 : 96;
|
||||
if (IS_I85X(dev_priv->dev))
|
||||
dev_priv->lvds_ssc_freq =
|
||||
general->ssc_freq ? 66 : 48;
|
||||
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)
|
||||
|
||||
temp = I915_READ(reg);
|
||||
temp &= ~(ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE);
|
||||
temp |= ADPA_DAC_ENABLE;
|
||||
temp &= ~ADPA_DAC_ENABLE;
|
||||
|
||||
switch(mode) {
|
||||
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)
|
||||
{
|
||||
int ret;
|
||||
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,
|
||||
|
@ -25,6 +25,7 @@
|
||||
*/
|
||||
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/kernel.h>
|
||||
#include "drmP.h"
|
||||
#include "intel_drv.h"
|
||||
#include "i915_drm.h"
|
||||
@ -34,6 +35,7 @@
|
||||
#include "drm_crtc_helper.h"
|
||||
|
||||
bool intel_pipe_has_type (struct drm_crtc *crtc, int type);
|
||||
static void intel_update_watermarks(struct drm_device *dev);
|
||||
|
||||
typedef struct {
|
||||
/* given values */
|
||||
@ -814,24 +816,21 @@ intel_find_pll_g4x_dp(const intel_limit_t *limit, struct drm_crtc *crtc,
|
||||
{
|
||||
intel_clock_t clock;
|
||||
if (target < 200000) {
|
||||
clock.dot = 161670;
|
||||
clock.p = 20;
|
||||
clock.p1 = 2;
|
||||
clock.p2 = 10;
|
||||
clock.n = 0x01;
|
||||
clock.m = 97;
|
||||
clock.m1 = 0x10;
|
||||
clock.m2 = 0x05;
|
||||
clock.n = 2;
|
||||
clock.m1 = 23;
|
||||
clock.m2 = 8;
|
||||
} else {
|
||||
clock.dot = 270000;
|
||||
clock.p = 10;
|
||||
clock.p1 = 1;
|
||||
clock.p2 = 10;
|
||||
clock.n = 0x02;
|
||||
clock.m = 108;
|
||||
clock.m1 = 0x12;
|
||||
clock.m2 = 0x06;
|
||||
clock.n = 1;
|
||||
clock.m1 = 14;
|
||||
clock.m2 = 2;
|
||||
}
|
||||
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));
|
||||
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 intel_crtc *intel_crtc = to_intel_crtc(crtc);
|
||||
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 pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF;
|
||||
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 */
|
||||
//intel_crtc_dpms_video(crtc, true); TODO
|
||||
intel_update_watermarks(dev);
|
||||
break;
|
||||
case DRM_MODE_DPMS_OFF:
|
||||
intel_update_watermarks(dev);
|
||||
/* Give the overlay scaler a chance to disable if it's on this pipe */
|
||||
//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 the pipe currently connected to the panel fitter,
|
||||
* 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 = 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;
|
||||
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,
|
||||
struct drm_display_mode *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 */
|
||||
ret = intel_pipe_set_base(crtc, x, y, old_fb);
|
||||
|
||||
intel_update_watermarks(dev);
|
||||
|
||||
drm_vblank_post_modeset(dev, pipe);
|
||||
|
||||
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);
|
||||
intel_crtc->pipe = pipe;
|
||||
intel_crtc->plane = pipe;
|
||||
for (i = 0; i < 256; i++) {
|
||||
intel_crtc->lut_r[i] = i;
|
||||
intel_crtc->lut_g[i] = i;
|
||||
|
@ -246,7 +246,7 @@ intel_dp_aux_ch(struct intel_output *intel_output,
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@ -254,11 +254,14 @@ intel_dp_aux_ch(struct intel_output *intel_output,
|
||||
* Timeouts occur when the sink is not connected
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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) {
|
||||
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;
|
||||
}
|
||||
|
||||
@ -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->lane_count = lane_count;
|
||||
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,
|
||||
adjusted_mode->clock);
|
||||
return true;
|
||||
|
@ -29,6 +29,7 @@
|
||||
#include <linux/sched.h>
|
||||
#include <linux/i2c.h>
|
||||
#include "intel_dp.h"
|
||||
#include "drmP.h"
|
||||
|
||||
/* 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,
|
||||
reply, reply_bytes);
|
||||
if (ret < 0) {
|
||||
printk(KERN_ERR "aux_ch failed %d\n", ret);
|
||||
DRM_DEBUG("aux_ch failed %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
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;
|
||||
case AUX_I2C_REPLY_NACK:
|
||||
printk(KERN_ERR "aux_ch nack\n");
|
||||
DRM_DEBUG("aux_ch nack\n");
|
||||
return -EREMOTEIO;
|
||||
case AUX_I2C_REPLY_DEFER:
|
||||
printk(KERN_ERR "aux_ch defer\n");
|
||||
DRM_DEBUG("aux_ch defer\n");
|
||||
udelay(100);
|
||||
break;
|
||||
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;
|
||||
}
|
||||
}
|
||||
@ -223,7 +224,7 @@ i2c_algo_dp_aux_xfer(struct i2c_adapter *adapter,
|
||||
if (ret >= 0)
|
||||
ret = num;
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -453,7 +453,7 @@ static int intelfb_create(struct drm_device *dev, uint32_t fb_width,
|
||||
size = ALIGN(size, PAGE_SIZE);
|
||||
fbo = drm_gem_object_alloc(dev, size);
|
||||
if (!fbo) {
|
||||
printk(KERN_ERR "failed to allocate framebuffer\n");
|
||||
DRM_ERROR("failed to allocate framebuffer\n");
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
@ -610,8 +610,8 @@ static int intelfb_create(struct drm_device *dev, uint32_t fb_width,
|
||||
par->dev = dev;
|
||||
|
||||
/* To allow resizeing without swapping buffers */
|
||||
printk("allocated %dx%d fb: 0x%08x, bo %p\n", intel_fb->base.width,
|
||||
intel_fb->base.height, obj_priv->gtt_offset, fbo);
|
||||
DRM_DEBUG("allocated %dx%d fb: 0x%08x, bo %p\n", intel_fb->base.width,
|
||||
intel_fb->base.height, obj_priv->gtt_offset, fbo);
|
||||
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
return 0;
|
||||
@ -698,13 +698,13 @@ static int intelfb_multi_fb_probe_crtc(struct drm_device *dev, struct drm_crtc *
|
||||
} else
|
||||
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);
|
||||
|
||||
/* Switch back to kernel console on panic */
|
||||
kernelfb_mode = *modeset;
|
||||
atomic_notifier_chain_register(&panic_notifier_list, &paniced);
|
||||
printk(KERN_INFO "registered panic notifier\n");
|
||||
DRM_DEBUG("registered panic notifier\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -852,13 +852,13 @@ static int intelfb_single_fb_probe(struct drm_device *dev)
|
||||
} else
|
||||
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);
|
||||
|
||||
/* Switch back to kernel console on panic */
|
||||
kernelfb_mode = *modeset;
|
||||
atomic_notifier_chain_register(&panic_notifier_list, &paniced);
|
||||
printk(KERN_INFO "registered panic notifier\n");
|
||||
DRM_DEBUG("registered panic notifier\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -872,8 +872,8 @@ void intelfb_restore(void)
|
||||
{
|
||||
int ret;
|
||||
if ((ret = drm_crtc_helper_set_config(&kernelfb_mode)) != 0) {
|
||||
printk(KERN_ERR "Failed to restore crtc configuration: %d\n",
|
||||
ret);
|
||||
DRM_ERROR("Failed to restore crtc configuration: %d\n",
|
||||
ret);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -36,6 +36,7 @@
|
||||
#include "intel_drv.h"
|
||||
#include "i915_drm.h"
|
||||
#include "i915_drv.h"
|
||||
#include <linux/acpi.h>
|
||||
|
||||
#define I915_LVDS "i915_lvds"
|
||||
|
||||
@ -252,14 +253,14 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder,
|
||||
|
||||
/* Should never happen!! */
|
||||
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;
|
||||
}
|
||||
|
||||
/* Should never happen!! */
|
||||
list_for_each_entry(tmp_encoder, &dev->mode_config.encoder_list, head) {
|
||||
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");
|
||||
return false;
|
||||
}
|
||||
@ -788,6 +789,65 @@ static const struct dmi_system_id intel_no_lvds[] = {
|
||||
{ } /* 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
|
||||
* @dev: drm device
|
||||
@ -811,6 +871,16 @@ void intel_lvds_init(struct drm_device *dev)
|
||||
if (dmi_check_system(intel_no_lvds))
|
||||
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 ((I915_READ(PCH_LVDS) & LVDS_DETECTED) == 0)
|
||||
return;
|
||||
|
@ -68,11 +68,22 @@ struct intel_sdvo_priv {
|
||||
* This is set if we treat the device as HDMI, instead of DVI.
|
||||
*/
|
||||
bool is_hdmi;
|
||||
|
||||
/**
|
||||
* This is set if we detect output of sdvo device as 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
|
||||
* device reported it.
|
||||
@ -592,6 +603,7 @@ intel_sdvo_create_preferred_input_timing(struct intel_output *output,
|
||||
uint16_t height)
|
||||
{
|
||||
struct intel_sdvo_preferred_input_timing_args args;
|
||||
struct intel_sdvo_priv *sdvo_priv = output->dev_priv;
|
||||
uint8_t status;
|
||||
|
||||
memset(&args, 0, sizeof(args));
|
||||
@ -599,7 +611,12 @@ intel_sdvo_create_preferred_input_timing(struct intel_output *output,
|
||||
args.width = width;
|
||||
args.height = height;
|
||||
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,
|
||||
&args, sizeof(args));
|
||||
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_sdvo_priv *dev_priv = output->dev_priv;
|
||||
|
||||
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 {
|
||||
if (dev_priv->is_tv) {
|
||||
struct intel_sdvo_dtd output_dtd;
|
||||
bool success;
|
||||
|
||||
@ -980,6 +992,7 @@ static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder,
|
||||
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);
|
||||
|
||||
@ -990,6 +1003,52 @@ static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder,
|
||||
} 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);
|
||||
|
||||
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;
|
||||
}
|
||||
@ -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
|
||||
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);
|
||||
else
|
||||
input_dtd.part2.sdvo_flags = sdvo_priv->sdvo_flags;
|
||||
} else
|
||||
intel_sdvo_get_dtd_from_mode(&input_dtd, mode);
|
||||
|
||||
/* If it's a TV, we already set the output timing in mode_fixup.
|
||||
* 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 */
|
||||
intel_sdvo_set_target_output(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;
|
||||
}
|
||||
|
||||
if (sdvo_priv->sdvo_flags & SDVO_NEED_TO_STALL)
|
||||
sdvox |= SDVO_STALL_SELECT;
|
||||
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)
|
||||
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;
|
||||
}
|
||||
|
||||
@ -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 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.
|
||||
@ -1557,11 +1632,10 @@ static void intel_sdvo_get_lvds_modes(struct drm_connector *connector)
|
||||
*/
|
||||
intel_ddc_get_modes(intel_output);
|
||||
if (list_empty(&connector->probed_modes) == false)
|
||||
return;
|
||||
goto end;
|
||||
|
||||
/* Fetch modes from VBT */
|
||||
if (dev_priv->sdvo_lvds_vbt_mode != NULL) {
|
||||
struct drm_display_mode *newmode;
|
||||
newmode = drm_mode_duplicate(connector->dev,
|
||||
dev_priv->sdvo_lvds_vbt_mode);
|
||||
if (newmode != NULL) {
|
||||
@ -1571,6 +1645,16 @@ static void intel_sdvo_get_lvds_modes(struct drm_connector *connector)
|
||||
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)
|
||||
@ -1593,14 +1677,20 @@ static int intel_sdvo_get_modes(struct drm_connector *connector)
|
||||
static void intel_sdvo_destroy(struct drm_connector *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)
|
||||
intel_i2c_destroy(intel_output->i2c_bus);
|
||||
if (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_connector_cleanup(connector);
|
||||
|
||||
kfree(intel_output);
|
||||
}
|
||||
|
||||
|
@ -715,6 +715,7 @@ struct intel_sdvo_enhancements_arg {
|
||||
#define SDVO_HBUF_TX_ONCE (2 << 6)
|
||||
#define SDVO_HBUF_TX_VSYNC (3 << 6)
|
||||
#define SDVO_CMD_GET_AUDIO_TX_INFO 0x9c
|
||||
#define SDVO_NEED_TO_STALL (1 << 7)
|
||||
|
||||
struct intel_sdvo_encode{
|
||||
u8 dvi_rev;
|
||||
|
Loading…
Reference in New Issue
Block a user