Merge branch 'drm-intel-next' of ../anholt-2.6 into drm-linus
This commit is contained in:
commit
5f3dbedf27
16 changed files with 292 additions and 123 deletions
|
@ -505,7 +505,6 @@ int drm_gem_mmap(struct file *filp, struct vm_area_struct *vma)
|
|||
struct drm_local_map *map = NULL;
|
||||
struct drm_gem_object *obj;
|
||||
struct drm_hash_item *hash;
|
||||
unsigned long prot;
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
|
@ -538,11 +537,7 @@ int drm_gem_mmap(struct file *filp, struct vm_area_struct *vma)
|
|||
vma->vm_ops = obj->dev->driver->gem_vm_ops;
|
||||
vma->vm_private_data = map->handle;
|
||||
/* FIXME: use pgprot_writecombine when available */
|
||||
prot = pgprot_val(vma->vm_page_prot);
|
||||
#ifdef CONFIG_X86
|
||||
prot |= _PAGE_CACHE_WC;
|
||||
#endif
|
||||
vma->vm_page_prot = __pgprot(prot);
|
||||
vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
|
||||
|
||||
/* Take a ref for this mapping of the object, so that the fault
|
||||
* handler can dereference the mmap offset's pointer to the object.
|
||||
|
|
|
@ -451,6 +451,7 @@ void drm_sysfs_hotplug_event(struct drm_device *dev)
|
|||
|
||||
kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, envp);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_sysfs_hotplug_event);
|
||||
|
||||
/**
|
||||
* drm_sysfs_device_add - adds a class device to sysfs for a character driver
|
||||
|
|
|
@ -922,7 +922,7 @@ static int i915_probe_agp(struct drm_device *dev, unsigned long *aperture_size,
|
|||
* Some of the preallocated space is taken by the GTT
|
||||
* and popup. GTT is 1K per MB of aperture size, and popup is 4K.
|
||||
*/
|
||||
if (IS_G4X(dev))
|
||||
if (IS_G4X(dev) || IS_IGD(dev))
|
||||
overhead = 4096;
|
||||
else
|
||||
overhead = (*aperture_size / 1024) + 4096;
|
||||
|
@ -1030,13 +1030,6 @@ static int i915_load_modeset_init(struct drm_device *dev)
|
|||
if (ret)
|
||||
goto destroy_ringbuffer;
|
||||
|
||||
/* FIXME: re-add hotplug support */
|
||||
#if 0
|
||||
ret = drm_hotplug_init(dev);
|
||||
if (ret)
|
||||
goto destroy_ringbuffer;
|
||||
#endif
|
||||
|
||||
/* Always safe in the mode setting case. */
|
||||
/* FIXME: do pre/post-mode set stuff in core KMS code */
|
||||
dev->vblank_disable_allowed = 1;
|
||||
|
|
|
@ -159,6 +159,9 @@ typedef struct drm_i915_private {
|
|||
u32 irq_mask_reg;
|
||||
u32 pipestat[2];
|
||||
|
||||
u32 hotplug_supported_mask;
|
||||
struct work_struct hotplug_work;
|
||||
|
||||
int tex_lru_log_granularity;
|
||||
int allow_batchbuffer;
|
||||
struct mem_block *agp_heap;
|
||||
|
@ -297,6 +300,7 @@ typedef struct drm_i915_private {
|
|||
*
|
||||
* A reference is held on the buffer while on this list.
|
||||
*/
|
||||
spinlock_t active_list_lock;
|
||||
struct list_head active_list;
|
||||
|
||||
/**
|
||||
|
@ -810,6 +814,7 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller);
|
|||
#define HAS_128_BYTE_Y_TILING(dev) (IS_I9XX(dev) && !(IS_I915G(dev) || \
|
||||
IS_I915GM(dev)))
|
||||
#define SUPPORTS_INTEGRATED_HDMI(dev) (IS_G4X(dev))
|
||||
#define I915_HAS_HOTPLUG(dev) (IS_I945G(dev) || IS_I945GM(dev) || IS_I965G(dev))
|
||||
|
||||
#define PRIMARY_RINGBUFFER_SIZE (128*1024)
|
||||
|
||||
|
|
|
@ -1072,6 +1072,7 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
|
|||
case -EAGAIN:
|
||||
return VM_FAULT_OOM;
|
||||
case -EFAULT:
|
||||
case -EINVAL:
|
||||
return VM_FAULT_SIGBUS;
|
||||
default:
|
||||
return VM_FAULT_NOPAGE;
|
||||
|
@ -1324,8 +1325,10 @@ i915_gem_object_move_to_active(struct drm_gem_object *obj, uint32_t seqno)
|
|||
obj_priv->active = 1;
|
||||
}
|
||||
/* Move from whatever list we were on to the tail of execution. */
|
||||
spin_lock(&dev_priv->mm.active_list_lock);
|
||||
list_move_tail(&obj_priv->list,
|
||||
&dev_priv->mm.active_list);
|
||||
spin_unlock(&dev_priv->mm.active_list_lock);
|
||||
obj_priv->last_rendering_seqno = seqno;
|
||||
}
|
||||
|
||||
|
@ -1467,6 +1470,7 @@ i915_gem_retire_request(struct drm_device *dev,
|
|||
/* Move any buffers on the active list that are no longer referenced
|
||||
* by the ringbuffer to the flushing/inactive lists as appropriate.
|
||||
*/
|
||||
spin_lock(&dev_priv->mm.active_list_lock);
|
||||
while (!list_empty(&dev_priv->mm.active_list)) {
|
||||
struct drm_gem_object *obj;
|
||||
struct drm_i915_gem_object *obj_priv;
|
||||
|
@ -1481,7 +1485,7 @@ i915_gem_retire_request(struct drm_device *dev,
|
|||
* this seqno.
|
||||
*/
|
||||
if (obj_priv->last_rendering_seqno != request->seqno)
|
||||
return;
|
||||
goto out;
|
||||
|
||||
#if WATCH_LRU
|
||||
DRM_INFO("%s: retire %d moves to inactive list %p\n",
|
||||
|
@ -1493,6 +1497,8 @@ i915_gem_retire_request(struct drm_device *dev,
|
|||
else
|
||||
i915_gem_object_move_to_inactive(obj);
|
||||
}
|
||||
out:
|
||||
spin_unlock(&dev_priv->mm.active_list_lock);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1990,20 +1996,23 @@ static void i830_write_fence_reg(struct drm_i915_fence_reg *reg)
|
|||
int regnum = obj_priv->fence_reg;
|
||||
uint32_t val;
|
||||
uint32_t pitch_val;
|
||||
uint32_t fence_size_bits;
|
||||
|
||||
if ((obj_priv->gtt_offset & ~I915_FENCE_START_MASK) ||
|
||||
if ((obj_priv->gtt_offset & ~I830_FENCE_START_MASK) ||
|
||||
(obj_priv->gtt_offset & (obj->size - 1))) {
|
||||
WARN(1, "%s: object 0x%08x not 1M or size aligned\n",
|
||||
WARN(1, "%s: object 0x%08x not 512K or size aligned\n",
|
||||
__func__, obj_priv->gtt_offset);
|
||||
return;
|
||||
}
|
||||
|
||||
pitch_val = (obj_priv->stride / 128) - 1;
|
||||
|
||||
WARN_ON(pitch_val & ~0x0000000f);
|
||||
val = obj_priv->gtt_offset;
|
||||
if (obj_priv->tiling_mode == I915_TILING_Y)
|
||||
val |= 1 << I830_FENCE_TILING_Y_SHIFT;
|
||||
val |= I830_FENCE_SIZE_BITS(obj->size);
|
||||
fence_size_bits = I830_FENCE_SIZE_BITS(obj->size);
|
||||
WARN_ON(fence_size_bits & ~0x00000f00);
|
||||
val |= fence_size_bits;
|
||||
val |= pitch_val << I830_FENCE_PITCH_SHIFT;
|
||||
val |= I830_FENCE_REG_VALID;
|
||||
|
||||
|
@ -2194,7 +2203,7 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment)
|
|||
return -EBUSY;
|
||||
if (alignment == 0)
|
||||
alignment = i915_gem_get_gtt_alignment(obj);
|
||||
if (alignment & (PAGE_SIZE - 1)) {
|
||||
if (alignment & (i915_gem_get_gtt_alignment(obj) - 1)) {
|
||||
DRM_ERROR("Invalid object alignment requested %u\n", alignment);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -2211,15 +2220,20 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment)
|
|||
}
|
||||
}
|
||||
if (obj_priv->gtt_space == NULL) {
|
||||
bool lists_empty;
|
||||
|
||||
/* If the gtt is empty and we're still having trouble
|
||||
* fitting our object in, we're out of memory.
|
||||
*/
|
||||
#if WATCH_LRU
|
||||
DRM_INFO("%s: GTT full, evicting something\n", __func__);
|
||||
#endif
|
||||
if (list_empty(&dev_priv->mm.inactive_list) &&
|
||||
list_empty(&dev_priv->mm.flushing_list) &&
|
||||
list_empty(&dev_priv->mm.active_list)) {
|
||||
spin_lock(&dev_priv->mm.active_list_lock);
|
||||
lists_empty = (list_empty(&dev_priv->mm.inactive_list) &&
|
||||
list_empty(&dev_priv->mm.flushing_list) &&
|
||||
list_empty(&dev_priv->mm.active_list));
|
||||
spin_unlock(&dev_priv->mm.active_list_lock);
|
||||
if (lists_empty) {
|
||||
DRM_ERROR("GTT full, but LRU list empty\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
@ -3675,6 +3689,7 @@ i915_gem_idle(struct drm_device *dev)
|
|||
|
||||
i915_gem_retire_requests(dev);
|
||||
|
||||
spin_lock(&dev_priv->mm.active_list_lock);
|
||||
if (!dev_priv->mm.wedged) {
|
||||
/* Active and flushing should now be empty as we've
|
||||
* waited for a sequence higher than any pending execbuffer
|
||||
|
@ -3701,6 +3716,7 @@ i915_gem_idle(struct drm_device *dev)
|
|||
obj_priv->obj->write_domain &= ~I915_GEM_GPU_DOMAINS;
|
||||
i915_gem_object_move_to_inactive(obj_priv->obj);
|
||||
}
|
||||
spin_unlock(&dev_priv->mm.active_list_lock);
|
||||
|
||||
while (!list_empty(&dev_priv->mm.flushing_list)) {
|
||||
struct drm_i915_gem_object *obj_priv;
|
||||
|
@ -3949,7 +3965,10 @@ i915_gem_entervt_ioctl(struct drm_device *dev, void *data,
|
|||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
spin_lock(&dev_priv->mm.active_list_lock);
|
||||
BUG_ON(!list_empty(&dev_priv->mm.active_list));
|
||||
spin_unlock(&dev_priv->mm.active_list_lock);
|
||||
|
||||
BUG_ON(!list_empty(&dev_priv->mm.flushing_list));
|
||||
BUG_ON(!list_empty(&dev_priv->mm.inactive_list));
|
||||
BUG_ON(!list_empty(&dev_priv->mm.request_list));
|
||||
|
@ -3993,6 +4012,7 @@ i915_gem_load(struct drm_device *dev)
|
|||
{
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
|
||||
spin_lock_init(&dev_priv->mm.active_list_lock);
|
||||
INIT_LIST_HEAD(&dev_priv->mm.active_list);
|
||||
INIT_LIST_HEAD(&dev_priv->mm.flushing_list);
|
||||
INIT_LIST_HEAD(&dev_priv->mm.inactive_list);
|
||||
|
|
|
@ -105,12 +105,14 @@ i915_dump_lru(struct drm_device *dev, const char *where)
|
|||
struct drm_i915_gem_object *obj_priv;
|
||||
|
||||
DRM_INFO("active list %s {\n", where);
|
||||
spin_lock(&dev_priv->mm.active_list_lock);
|
||||
list_for_each_entry(obj_priv, &dev_priv->mm.active_list,
|
||||
list)
|
||||
{
|
||||
DRM_INFO(" %p: %08x\n", obj_priv,
|
||||
obj_priv->last_rendering_seqno);
|
||||
}
|
||||
spin_unlock(&dev_priv->mm.active_list_lock);
|
||||
DRM_INFO("}\n");
|
||||
DRM_INFO("flushing list %s {\n", where);
|
||||
list_for_each_entry(obj_priv, &dev_priv->mm.flushing_list,
|
||||
|
|
|
@ -69,10 +69,13 @@ static int i915_gem_object_list_info(struct seq_file *m, void *data)
|
|||
struct drm_device *dev = node->minor->dev;
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
struct drm_i915_gem_object *obj_priv;
|
||||
spinlock_t *lock = NULL;
|
||||
|
||||
switch (list) {
|
||||
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:
|
||||
|
@ -104,6 +107,9 @@ static int i915_gem_object_list_info(struct seq_file *m, void *data)
|
|||
seq_printf(m, " (fence: %d\n", obj_priv->fence_reg);
|
||||
seq_printf(m, "\n");
|
||||
}
|
||||
|
||||
if (lock)
|
||||
spin_unlock(lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -216,6 +216,22 @@ i915_tiling_ok(struct drm_device *dev, int stride, int size, int tiling_mode)
|
|||
else
|
||||
tile_width = 512;
|
||||
|
||||
/* check maximum stride & object size */
|
||||
if (IS_I965G(dev)) {
|
||||
/* i965 stores the end address of the gtt mapping in the fence
|
||||
* reg, so dont bother to check the size */
|
||||
if (stride / 128 > I965_FENCE_MAX_PITCH_VAL)
|
||||
return false;
|
||||
} else if (IS_I9XX(dev)) {
|
||||
if (stride / tile_width > I830_FENCE_MAX_PITCH_VAL ||
|
||||
size > (I830_FENCE_MAX_SIZE_VAL << 20))
|
||||
return false;
|
||||
} else {
|
||||
if (stride / 128 > I830_FENCE_MAX_PITCH_VAL ||
|
||||
size > (I830_FENCE_MAX_SIZE_VAL << 19))
|
||||
return false;
|
||||
}
|
||||
|
||||
/* 965+ just needs multiples of tile width */
|
||||
if (IS_I965G(dev)) {
|
||||
if (stride & (tile_width - 1))
|
||||
|
|
|
@ -48,10 +48,6 @@
|
|||
/** Interrupts that we mask and unmask at runtime. */
|
||||
#define I915_INTERRUPT_ENABLE_VAR (I915_USER_INTERRUPT)
|
||||
|
||||
/** These are all of the interrupts used by the driver */
|
||||
#define I915_INTERRUPT_ENABLE_MASK (I915_INTERRUPT_ENABLE_FIX | \
|
||||
I915_INTERRUPT_ENABLE_VAR)
|
||||
|
||||
#define I915_PIPE_VBLANK_STATUS (PIPE_START_VBLANK_INTERRUPT_STATUS |\
|
||||
PIPE_VBLANK_INTERRUPT_STATUS)
|
||||
|
||||
|
@ -187,6 +183,19 @@ u32 gm45_get_vblank_counter(struct drm_device *dev, int pipe)
|
|||
return I915_READ(reg);
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle hotplug events outside the interrupt handler proper.
|
||||
*/
|
||||
static void i915_hotplug_work_func(struct work_struct *work)
|
||||
{
|
||||
drm_i915_private_t *dev_priv = container_of(work, drm_i915_private_t,
|
||||
hotplug_work);
|
||||
struct drm_device *dev = dev_priv->dev;
|
||||
|
||||
/* Just fire off a uevent and let userspace tell us what to do */
|
||||
drm_sysfs_hotplug_event(dev);
|
||||
}
|
||||
|
||||
irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
|
||||
{
|
||||
struct drm_device *dev = (struct drm_device *) arg;
|
||||
|
@ -244,6 +253,20 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
|
|||
|
||||
ret = IRQ_HANDLED;
|
||||
|
||||
/* Consume port. Then clear IIR or we'll miss events */
|
||||
if ((I915_HAS_HOTPLUG(dev)) &&
|
||||
(iir & I915_DISPLAY_PORT_INTERRUPT)) {
|
||||
u32 hotplug_status = I915_READ(PORT_HOTPLUG_STAT);
|
||||
|
||||
DRM_DEBUG("hotplug event received, stat 0x%08x\n",
|
||||
hotplug_status);
|
||||
if (hotplug_status & dev_priv->hotplug_supported_mask)
|
||||
schedule_work(&dev_priv->hotplug_work);
|
||||
|
||||
I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status);
|
||||
I915_READ(PORT_HOTPLUG_STAT);
|
||||
}
|
||||
|
||||
I915_WRITE(IIR, iir);
|
||||
new_iir = I915_READ(IIR); /* Flush posted writes */
|
||||
|
||||
|
@ -528,17 +551,24 @@ void i915_driver_irq_preinstall(struct drm_device * dev)
|
|||
|
||||
atomic_set(&dev_priv->irq_received, 0);
|
||||
|
||||
if (I915_HAS_HOTPLUG(dev)) {
|
||||
I915_WRITE(PORT_HOTPLUG_EN, 0);
|
||||
I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
|
||||
}
|
||||
|
||||
I915_WRITE(HWSTAM, 0xeffe);
|
||||
I915_WRITE(PIPEASTAT, 0);
|
||||
I915_WRITE(PIPEBSTAT, 0);
|
||||
I915_WRITE(IMR, 0xffffffff);
|
||||
I915_WRITE(IER, 0x0);
|
||||
(void) I915_READ(IER);
|
||||
INIT_WORK(&dev_priv->hotplug_work, i915_hotplug_work_func);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B;
|
||||
|
||||
|
@ -550,13 +580,35 @@ int i915_driver_irq_postinstall(struct drm_device *dev)
|
|||
dev_priv->pipestat[0] = 0;
|
||||
dev_priv->pipestat[1] = 0;
|
||||
|
||||
if (I915_HAS_HOTPLUG(dev)) {
|
||||
u32 hotplug_en = I915_READ(PORT_HOTPLUG_EN);
|
||||
|
||||
/* Leave other bits alone */
|
||||
hotplug_en |= HOTPLUG_EN_MASK;
|
||||
I915_WRITE(PORT_HOTPLUG_EN, hotplug_en);
|
||||
|
||||
dev_priv->hotplug_supported_mask = CRT_HOTPLUG_INT_STATUS |
|
||||
TV_HOTPLUG_INT_STATUS | SDVOC_HOTPLUG_INT_STATUS |
|
||||
SDVOB_HOTPLUG_INT_STATUS;
|
||||
if (IS_G4X(dev)) {
|
||||
dev_priv->hotplug_supported_mask |=
|
||||
HDMIB_HOTPLUG_INT_STATUS |
|
||||
HDMIC_HOTPLUG_INT_STATUS |
|
||||
HDMID_HOTPLUG_INT_STATUS;
|
||||
}
|
||||
/* Enable in IER... */
|
||||
enable_mask |= I915_DISPLAY_PORT_INTERRUPT;
|
||||
/* and unmask in IMR */
|
||||
i915_enable_irq(dev_priv, I915_DISPLAY_PORT_INTERRUPT);
|
||||
}
|
||||
|
||||
/* Disable pipe interrupt enables, clear pending pipe status */
|
||||
I915_WRITE(PIPEASTAT, I915_READ(PIPEASTAT) & 0x8000ffff);
|
||||
I915_WRITE(PIPEBSTAT, I915_READ(PIPEBSTAT) & 0x8000ffff);
|
||||
/* Clear pending interrupt status */
|
||||
I915_WRITE(IIR, I915_READ(IIR));
|
||||
|
||||
I915_WRITE(IER, I915_INTERRUPT_ENABLE_MASK);
|
||||
I915_WRITE(IER, enable_mask);
|
||||
I915_WRITE(IMR, dev_priv->irq_mask_reg);
|
||||
(void) I915_READ(IER);
|
||||
|
||||
|
@ -575,6 +627,11 @@ void i915_driver_irq_uninstall(struct drm_device * dev)
|
|||
|
||||
dev_priv->vblank_pipe = 0;
|
||||
|
||||
if (I915_HAS_HOTPLUG(dev)) {
|
||||
I915_WRITE(PORT_HOTPLUG_EN, 0);
|
||||
I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
|
||||
}
|
||||
|
||||
I915_WRITE(HWSTAM, 0xffffffff);
|
||||
I915_WRITE(PIPEASTAT, 0);
|
||||
I915_WRITE(PIPEBSTAT, 0);
|
||||
|
|
|
@ -190,6 +190,8 @@
|
|||
#define I830_FENCE_SIZE_BITS(size) ((ffs((size) >> 19) - 1) << 8)
|
||||
#define I830_FENCE_PITCH_SHIFT 4
|
||||
#define I830_FENCE_REG_VALID (1<<0)
|
||||
#define I830_FENCE_MAX_PITCH_VAL 0x10
|
||||
#define I830_FENCE_MAX_SIZE_VAL (1<<8)
|
||||
|
||||
#define I915_FENCE_START_MASK 0x0ff00000
|
||||
#define I915_FENCE_SIZE_BITS(size) ((ffs((size) >> 20) - 1) << 8)
|
||||
|
@ -198,6 +200,7 @@
|
|||
#define I965_FENCE_PITCH_SHIFT 2
|
||||
#define I965_FENCE_TILING_Y_SHIFT 1
|
||||
#define I965_FENCE_REG_VALID (1<<0)
|
||||
#define I965_FENCE_MAX_PITCH_VAL 0x0400
|
||||
|
||||
/*
|
||||
* Instruction and interrupt control regs
|
||||
|
@ -648,6 +651,14 @@
|
|||
#define CRT_HOTPLUG_DETECT_VOLTAGE_325MV (0 << 2)
|
||||
#define CRT_HOTPLUG_DETECT_VOLTAGE_475MV (1 << 2)
|
||||
#define CRT_HOTPLUG_MASK (0x3fc) /* Bits 9-2 */
|
||||
#define CRT_FORCE_HOTPLUG_MASK 0xfffffe1f
|
||||
#define HOTPLUG_EN_MASK (HDMIB_HOTPLUG_INT_EN | \
|
||||
HDMIC_HOTPLUG_INT_EN | \
|
||||
HDMID_HOTPLUG_INT_EN | \
|
||||
SDVOB_HOTPLUG_INT_EN | \
|
||||
SDVOC_HOTPLUG_INT_EN | \
|
||||
TV_HOTPLUG_INT_EN | \
|
||||
CRT_HOTPLUG_INT_EN)
|
||||
|
||||
|
||||
#define PORT_HOTPLUG_STAT 0x61114
|
||||
|
|
|
@ -41,7 +41,7 @@ static void intel_crt_dpms(struct drm_encoder *encoder, int mode)
|
|||
|
||||
temp = I915_READ(ADPA);
|
||||
temp &= ~(ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE);
|
||||
temp &= ~ADPA_DAC_ENABLE;
|
||||
temp |= ADPA_DAC_ENABLE;
|
||||
|
||||
switch(mode) {
|
||||
case DRM_MODE_DPMS_ON:
|
||||
|
@ -158,7 +158,7 @@ static bool intel_crt_detect_hotplug(struct drm_connector *connector)
|
|||
else
|
||||
tries = 1;
|
||||
hotplug_en = I915_READ(PORT_HOTPLUG_EN);
|
||||
hotplug_en &= ~(CRT_HOTPLUG_MASK);
|
||||
hotplug_en &= CRT_FORCE_HOTPLUG_MASK;
|
||||
hotplug_en |= CRT_HOTPLUG_FORCE_DETECT;
|
||||
|
||||
if (IS_GM45(dev))
|
||||
|
|
|
@ -636,7 +636,7 @@ void
|
|||
intel_wait_for_vblank(struct drm_device *dev)
|
||||
{
|
||||
/* Wait for 20ms, i.e. one cycle at 50hz. */
|
||||
udelay(20000);
|
||||
mdelay(20);
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -1106,6 +1106,26 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* SDVO TV has fixed PLL values depend on its clock range,
|
||||
this mirrors vbios setting. */
|
||||
if (is_sdvo && is_tv) {
|
||||
if (adjusted_mode->clock >= 100000
|
||||
&& adjusted_mode->clock < 140500) {
|
||||
clock.p1 = 2;
|
||||
clock.p2 = 10;
|
||||
clock.n = 3;
|
||||
clock.m1 = 16;
|
||||
clock.m2 = 8;
|
||||
} else if (adjusted_mode->clock >= 140500
|
||||
&& adjusted_mode->clock <= 200000) {
|
||||
clock.p1 = 1;
|
||||
clock.p2 = 10;
|
||||
clock.n = 6;
|
||||
clock.m1 = 12;
|
||||
clock.m2 = 8;
|
||||
}
|
||||
}
|
||||
|
||||
if (IS_IGD(dev))
|
||||
fp = (1 << clock.n) << 16 | clock.m1 << 8 | clock.m2;
|
||||
else
|
||||
|
|
|
@ -76,6 +76,7 @@ int intel_ddc_get_modes(struct intel_output *intel_output)
|
|||
drm_mode_connector_update_edid_property(&intel_output->base,
|
||||
edid);
|
||||
ret = drm_add_edid_modes(&intel_output->base, edid);
|
||||
intel_output->base.display_info.raw_edid = NULL;
|
||||
kfree(edid);
|
||||
}
|
||||
|
||||
|
|
|
@ -273,20 +273,20 @@ static void intel_sdvo_debug_write(struct intel_output *intel_output, u8 cmd,
|
|||
struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
|
||||
int i;
|
||||
|
||||
DRM_DEBUG("%s: W: %02X ", SDVO_NAME(sdvo_priv), cmd);
|
||||
printk(KERN_DEBUG "%s: W: %02X ", SDVO_NAME(sdvo_priv), cmd);
|
||||
for (i = 0; i < args_len; i++)
|
||||
printk("%02X ", ((u8 *)args)[i]);
|
||||
printk(KERN_DEBUG "%02X ", ((u8 *)args)[i]);
|
||||
for (; i < 8; i++)
|
||||
printk(" ");
|
||||
printk(KERN_DEBUG " ");
|
||||
for (i = 0; i < sizeof(sdvo_cmd_names) / sizeof(sdvo_cmd_names[0]); i++) {
|
||||
if (cmd == sdvo_cmd_names[i].cmd) {
|
||||
printk("(%s)", sdvo_cmd_names[i].name);
|
||||
printk(KERN_DEBUG "(%s)", sdvo_cmd_names[i].name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == sizeof(sdvo_cmd_names)/ sizeof(sdvo_cmd_names[0]))
|
||||
printk("(%02X)",cmd);
|
||||
printk("\n");
|
||||
printk(KERN_DEBUG "(%02X)", cmd);
|
||||
printk(KERN_DEBUG "\n");
|
||||
}
|
||||
#else
|
||||
#define intel_sdvo_debug_write(o, c, a, l)
|
||||
|
@ -323,17 +323,18 @@ static void intel_sdvo_debug_response(struct intel_output *intel_output,
|
|||
u8 status)
|
||||
{
|
||||
struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
|
||||
int i;
|
||||
|
||||
DRM_DEBUG("%s: R: ", SDVO_NAME(sdvo_priv));
|
||||
printk(KERN_DEBUG "%s: R: ", SDVO_NAME(sdvo_priv));
|
||||
for (i = 0; i < response_len; i++)
|
||||
printk("%02X ", ((u8 *)response)[i]);
|
||||
printk(KERN_DEBUG "%02X ", ((u8 *)response)[i]);
|
||||
for (; i < 8; i++)
|
||||
printk(" ");
|
||||
printk(KERN_DEBUG " ");
|
||||
if (status <= SDVO_CMD_STATUS_SCALING_NOT_SUPP)
|
||||
printk("(%s)", cmd_status_names[status]);
|
||||
printk(KERN_DEBUG "(%s)", cmd_status_names[status]);
|
||||
else
|
||||
printk("(??? %d)", status);
|
||||
printk("\n");
|
||||
printk(KERN_DEBUG "(??? %d)", status);
|
||||
printk(KERN_DEBUG "\n");
|
||||
}
|
||||
#else
|
||||
#define intel_sdvo_debug_response(o, r, l, s)
|
||||
|
@ -588,9 +589,12 @@ intel_sdvo_create_preferred_input_timing(struct intel_output *output,
|
|||
struct intel_sdvo_preferred_input_timing_args args;
|
||||
uint8_t status;
|
||||
|
||||
memset(&args, 0, sizeof(args));
|
||||
args.clock = clock;
|
||||
args.width = width;
|
||||
args.height = height;
|
||||
args.interlace = 0;
|
||||
args.scaled = 0;
|
||||
intel_sdvo_write_cmd(output, SDVO_CMD_CREATE_PREFERRED_INPUT_TIMING,
|
||||
&args, sizeof(args));
|
||||
status = intel_sdvo_read_response(output, NULL, 0);
|
||||
|
@ -683,7 +687,7 @@ static void intel_sdvo_get_dtd_from_mode(struct intel_sdvo_dtd *dtd,
|
|||
dtd->part1.v_high = (((height >> 8) & 0xf) << 4) |
|
||||
((v_blank_len >> 8) & 0xf);
|
||||
|
||||
dtd->part2.h_sync_off = h_sync_offset;
|
||||
dtd->part2.h_sync_off = h_sync_offset & 0xff;
|
||||
dtd->part2.h_sync_width = h_sync_len & 0xff;
|
||||
dtd->part2.v_sync_off_width = (v_sync_offset & 0xf) << 4 |
|
||||
(v_sync_len & 0xf);
|
||||
|
@ -705,27 +709,10 @@ static void intel_sdvo_get_dtd_from_mode(struct intel_sdvo_dtd *dtd,
|
|||
static void intel_sdvo_get_mode_from_dtd(struct drm_display_mode * mode,
|
||||
struct intel_sdvo_dtd *dtd)
|
||||
{
|
||||
uint16_t width, height;
|
||||
uint16_t h_blank_len, h_sync_len, v_blank_len, v_sync_len;
|
||||
uint16_t h_sync_offset, v_sync_offset;
|
||||
|
||||
width = mode->crtc_hdisplay;
|
||||
height = mode->crtc_vdisplay;
|
||||
|
||||
/* do some mode translations */
|
||||
h_blank_len = mode->crtc_hblank_end - mode->crtc_hblank_start;
|
||||
h_sync_len = mode->crtc_hsync_end - mode->crtc_hsync_start;
|
||||
|
||||
v_blank_len = mode->crtc_vblank_end - mode->crtc_vblank_start;
|
||||
v_sync_len = mode->crtc_vsync_end - mode->crtc_vsync_start;
|
||||
|
||||
h_sync_offset = mode->crtc_hsync_start - mode->crtc_hblank_start;
|
||||
v_sync_offset = mode->crtc_vsync_start - mode->crtc_vblank_start;
|
||||
|
||||
mode->hdisplay = dtd->part1.h_active;
|
||||
mode->hdisplay += ((dtd->part1.h_high >> 4) & 0x0f) << 8;
|
||||
mode->hsync_start = mode->hdisplay + dtd->part2.h_sync_off;
|
||||
mode->hsync_start += (dtd->part2.sync_off_width_high & 0xa0) << 2;
|
||||
mode->hsync_start += (dtd->part2.sync_off_width_high & 0xc0) << 2;
|
||||
mode->hsync_end = mode->hsync_start + dtd->part2.h_sync_width;
|
||||
mode->hsync_end += (dtd->part2.sync_off_width_high & 0x30) << 4;
|
||||
mode->htotal = mode->hdisplay + dtd->part1.h_blank;
|
||||
|
@ -735,7 +722,7 @@ static void intel_sdvo_get_mode_from_dtd(struct drm_display_mode * mode,
|
|||
mode->vdisplay += ((dtd->part1.v_high >> 4) & 0x0f) << 8;
|
||||
mode->vsync_start = mode->vdisplay;
|
||||
mode->vsync_start += (dtd->part2.v_sync_off_width >> 4) & 0xf;
|
||||
mode->vsync_start += (dtd->part2.sync_off_width_high & 0x0a) << 2;
|
||||
mode->vsync_start += (dtd->part2.sync_off_width_high & 0x0c) << 2;
|
||||
mode->vsync_start += dtd->part2.v_sync_off_high & 0xc0;
|
||||
mode->vsync_end = mode->vsync_start +
|
||||
(dtd->part2.v_sync_off_width & 0xf);
|
||||
|
@ -745,7 +732,7 @@ static void intel_sdvo_get_mode_from_dtd(struct drm_display_mode * mode,
|
|||
|
||||
mode->clock = dtd->part1.clock * 10;
|
||||
|
||||
mode->flags &= (DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC);
|
||||
mode->flags &= ~(DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC);
|
||||
if (dtd->part2.dtd_flags & 0x2)
|
||||
mode->flags |= DRM_MODE_FLAG_PHSYNC;
|
||||
if (dtd->part2.dtd_flags & 0x4)
|
||||
|
@ -924,6 +911,27 @@ static void intel_sdvo_set_avi_infoframe(struct intel_output *output,
|
|||
SDVO_HBUF_TX_VSYNC);
|
||||
}
|
||||
|
||||
static void intel_sdvo_set_tv_format(struct intel_output *output)
|
||||
{
|
||||
struct intel_sdvo_priv *sdvo_priv = output->dev_priv;
|
||||
struct intel_sdvo_tv_format *format, unset;
|
||||
u8 status;
|
||||
|
||||
format = &sdvo_priv->tv_format;
|
||||
memset(&unset, 0, sizeof(unset));
|
||||
if (memcmp(format, &unset, sizeof(*format))) {
|
||||
DRM_DEBUG("%s: Choosing default TV format of NTSC-M\n",
|
||||
SDVO_NAME(sdvo_priv));
|
||||
format->ntsc_m = 1;
|
||||
intel_sdvo_write_cmd(output, SDVO_CMD_SET_TV_FORMAT, format,
|
||||
sizeof(*format));
|
||||
status = intel_sdvo_read_response(output, NULL, 0);
|
||||
if (status != SDVO_CMD_STATUS_SUCCESS)
|
||||
DRM_DEBUG("%s: Failed to set TV format\n",
|
||||
SDVO_NAME(sdvo_priv));
|
||||
}
|
||||
}
|
||||
|
||||
static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder,
|
||||
struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode)
|
||||
|
@ -968,6 +976,12 @@ static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder,
|
|||
&input_dtd);
|
||||
intel_sdvo_get_mode_from_dtd(adjusted_mode, &input_dtd);
|
||||
|
||||
drm_mode_set_crtcinfo(adjusted_mode, 0);
|
||||
|
||||
mode->clock = adjusted_mode->clock;
|
||||
|
||||
adjusted_mode->clock *=
|
||||
intel_sdvo_get_pixel_multiplier(mode);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
@ -1012,7 +1026,12 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder,
|
|||
sdvox |= SDVO_AUDIO_ENABLE;
|
||||
}
|
||||
|
||||
intel_sdvo_get_dtd_from_mode(&input_dtd, mode);
|
||||
/* We have tried to get input timing in mode_fixup, and filled into
|
||||
adjusted_mode */
|
||||
if (sdvo_priv->is_tv)
|
||||
intel_sdvo_get_dtd_from_mode(&input_dtd, adjusted_mode);
|
||||
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.
|
||||
|
@ -1027,6 +1046,9 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder,
|
|||
/* Set the input timing to the screen. Assume always input 0. */
|
||||
intel_sdvo_set_target_input(output, true, false);
|
||||
|
||||
if (sdvo_priv->is_tv)
|
||||
intel_sdvo_set_tv_format(output);
|
||||
|
||||
/* We would like to use intel_sdvo_create_preferred_input_timing() to
|
||||
* provide the device with a timing it can support, if it supports that
|
||||
* feature. However, presumably we would need to adjust the CRTC to
|
||||
|
@ -1395,7 +1417,7 @@ static void
|
|||
intel_sdvo_check_tv_format(struct intel_output *output)
|
||||
{
|
||||
struct intel_sdvo_priv *dev_priv = output->dev_priv;
|
||||
struct intel_sdvo_tv_format format, unset;
|
||||
struct intel_sdvo_tv_format format;
|
||||
uint8_t status;
|
||||
|
||||
intel_sdvo_write_cmd(output, SDVO_CMD_GET_TV_FORMAT, NULL, 0);
|
||||
|
@ -1403,15 +1425,7 @@ intel_sdvo_check_tv_format(struct intel_output *output)
|
|||
if (status != SDVO_CMD_STATUS_SUCCESS)
|
||||
return;
|
||||
|
||||
memset(&unset, 0, sizeof(unset));
|
||||
if (memcmp(&format, &unset, sizeof(format))) {
|
||||
DRM_DEBUG("%s: Choosing default TV format of NTSC-M\n",
|
||||
SDVO_NAME(dev_priv));
|
||||
|
||||
format.ntsc_m = true;
|
||||
intel_sdvo_write_cmd(output, SDVO_CMD_SET_TV_FORMAT, NULL, 0);
|
||||
status = intel_sdvo_read_response(output, NULL, 0);
|
||||
}
|
||||
memcpy(&dev_priv->tv_format, &format, sizeof(format));
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1420,68 +1434,70 @@ intel_sdvo_check_tv_format(struct intel_output *output)
|
|||
* XXX: all 60Hz refresh?
|
||||
*/
|
||||
struct drm_display_mode sdvo_tv_modes[] = {
|
||||
{ DRM_MODE("320x200", DRM_MODE_TYPE_DRIVER, 5815680, 321, 384, 416,
|
||||
200, 0, 232, 201, 233, 4196112, 0,
|
||||
{ DRM_MODE("320x200", DRM_MODE_TYPE_DRIVER, 5815, 320, 321, 384,
|
||||
416, 0, 200, 201, 232, 233, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
{ DRM_MODE("320x240", DRM_MODE_TYPE_DRIVER, 6814080, 321, 384, 416,
|
||||
240, 0, 272, 241, 273, 4196112, 0,
|
||||
{ DRM_MODE("320x240", DRM_MODE_TYPE_DRIVER, 6814, 320, 321, 384,
|
||||
416, 0, 240, 241, 272, 273, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
{ DRM_MODE("400x300", DRM_MODE_TYPE_DRIVER, 9910080, 401, 464, 496,
|
||||
300, 0, 332, 301, 333, 4196112, 0,
|
||||
{ DRM_MODE("400x300", DRM_MODE_TYPE_DRIVER, 9910, 400, 401, 464,
|
||||
496, 0, 300, 301, 332, 333, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
{ DRM_MODE("640x350", DRM_MODE_TYPE_DRIVER, 16913280, 641, 704, 736,
|
||||
350, 0, 382, 351, 383, 4196112, 0,
|
||||
{ DRM_MODE("640x350", DRM_MODE_TYPE_DRIVER, 16913, 640, 641, 704,
|
||||
736, 0, 350, 351, 382, 383, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
{ DRM_MODE("640x400", DRM_MODE_TYPE_DRIVER, 19121280, 641, 704, 736,
|
||||
400, 0, 432, 401, 433, 4196112, 0,
|
||||
{ DRM_MODE("640x400", DRM_MODE_TYPE_DRIVER, 19121, 640, 641, 704,
|
||||
736, 0, 400, 401, 432, 433, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
{ DRM_MODE("640x400", DRM_MODE_TYPE_DRIVER, 19121280, 641, 704, 736,
|
||||
400, 0, 432, 401, 433, 4196112, 0,
|
||||
{ DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 22654, 640, 641, 704,
|
||||
736, 0, 480, 481, 512, 513, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
{ DRM_MODE("704x480", DRM_MODE_TYPE_DRIVER, 24624000, 705, 768, 800,
|
||||
480, 0, 512, 481, 513, 4196112, 0,
|
||||
{ DRM_MODE("704x480", DRM_MODE_TYPE_DRIVER, 24624, 704, 705, 768,
|
||||
800, 0, 480, 481, 512, 513, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
{ DRM_MODE("704x576", DRM_MODE_TYPE_DRIVER, 29232000, 705, 768, 800,
|
||||
576, 0, 608, 577, 609, 4196112, 0,
|
||||
{ DRM_MODE("704x576", DRM_MODE_TYPE_DRIVER, 29232, 704, 705, 768,
|
||||
800, 0, 576, 577, 608, 609, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
{ DRM_MODE("720x350", DRM_MODE_TYPE_DRIVER, 18751680, 721, 784, 816,
|
||||
350, 0, 382, 351, 383, 4196112, 0,
|
||||
{ DRM_MODE("720x350", DRM_MODE_TYPE_DRIVER, 18751, 720, 721, 784,
|
||||
816, 0, 350, 351, 382, 383, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
{ DRM_MODE("720x400", DRM_MODE_TYPE_DRIVER, 21199680, 721, 784, 816,
|
||||
400, 0, 432, 401, 433, 4196112, 0,
|
||||
{ DRM_MODE("720x400", DRM_MODE_TYPE_DRIVER, 21199, 720, 721, 784,
|
||||
816, 0, 400, 401, 432, 433, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
{ DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 25116480, 721, 784, 816,
|
||||
480, 0, 512, 481, 513, 4196112, 0,
|
||||
{ DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 25116, 720, 721, 784,
|
||||
816, 0, 480, 481, 512, 513, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
{ DRM_MODE("720x540", DRM_MODE_TYPE_DRIVER, 28054080, 721, 784, 816,
|
||||
540, 0, 572, 541, 573, 4196112, 0,
|
||||
{ DRM_MODE("720x540", DRM_MODE_TYPE_DRIVER, 28054, 720, 721, 784,
|
||||
816, 0, 540, 541, 572, 573, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
{ DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 29816640, 721, 784, 816,
|
||||
576, 0, 608, 577, 609, 4196112, 0,
|
||||
{ DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 29816, 720, 721, 784,
|
||||
816, 0, 576, 577, 608, 609, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
{ DRM_MODE("768x576", DRM_MODE_TYPE_DRIVER, 31570560, 769, 832, 864,
|
||||
576, 0, 608, 577, 609, 4196112, 0,
|
||||
{ DRM_MODE("768x576", DRM_MODE_TYPE_DRIVER, 31570, 768, 769, 832,
|
||||
864, 0, 576, 577, 608, 609, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
{ DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 34030080, 801, 864, 896,
|
||||
600, 0, 632, 601, 633, 4196112, 0,
|
||||
{ DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 34030, 800, 801, 864,
|
||||
896, 0, 600, 601, 632, 633, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
{ DRM_MODE("832x624", DRM_MODE_TYPE_DRIVER, 36581760, 833, 896, 928,
|
||||
624, 0, 656, 625, 657, 4196112, 0,
|
||||
{ DRM_MODE("832x624", DRM_MODE_TYPE_DRIVER, 36581, 832, 833, 896,
|
||||
928, 0, 624, 625, 656, 657, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
{ DRM_MODE("920x766", DRM_MODE_TYPE_DRIVER, 48707040, 921, 984, 1016,
|
||||
766, 0, 798, 767, 799, 4196112, 0,
|
||||
{ DRM_MODE("920x766", DRM_MODE_TYPE_DRIVER, 48707, 920, 921, 984,
|
||||
1016, 0, 766, 767, 798, 799, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
{ DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 53827200, 1025, 1088, 1120,
|
||||
768, 0, 800, 769, 801, 4196112, 0,
|
||||
{ DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 53827, 1024, 1025, 1088,
|
||||
1120, 0, 768, 769, 800, 801, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
{ DRM_MODE("1280x1024", DRM_MODE_TYPE_DRIVER, 87265920, 1281, 1344, 1376,
|
||||
1024, 0, 1056, 1025, 1057, 4196112, 0,
|
||||
{ DRM_MODE("1280x1024", DRM_MODE_TYPE_DRIVER, 87265, 1280, 1281, 1344,
|
||||
1376, 0, 1024, 1025, 1056, 1057, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
};
|
||||
|
||||
static void intel_sdvo_get_tv_modes(struct drm_connector *connector)
|
||||
{
|
||||
struct intel_output *output = to_intel_output(connector);
|
||||
struct intel_sdvo_priv *sdvo_priv = output->dev_priv;
|
||||
struct intel_sdvo_sdtv_resolution_request tv_res;
|
||||
uint32_t reply = 0;
|
||||
uint8_t status;
|
||||
int i = 0;
|
||||
|
@ -1491,15 +1507,22 @@ static void intel_sdvo_get_tv_modes(struct drm_connector *connector)
|
|||
/* Read the list of supported input resolutions for the selected TV
|
||||
* format.
|
||||
*/
|
||||
memset(&tv_res, 0, sizeof(tv_res));
|
||||
memcpy(&tv_res, &sdvo_priv->tv_format, sizeof(tv_res));
|
||||
intel_sdvo_write_cmd(output, SDVO_CMD_GET_SDTV_RESOLUTION_SUPPORT,
|
||||
NULL, 0);
|
||||
&tv_res, sizeof(tv_res));
|
||||
status = intel_sdvo_read_response(output, &reply, 3);
|
||||
if (status != SDVO_CMD_STATUS_SUCCESS)
|
||||
return;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(sdvo_tv_modes); i++)
|
||||
if (reply & (1 << i))
|
||||
drm_mode_probed_add(connector, &sdvo_tv_modes[i]);
|
||||
if (reply & (1 << i)) {
|
||||
struct drm_display_mode *nmode;
|
||||
nmode = drm_mode_duplicate(connector->dev,
|
||||
&sdvo_tv_modes[i]);
|
||||
if (nmode)
|
||||
drm_mode_probed_add(connector, nmode);
|
||||
}
|
||||
}
|
||||
|
||||
static int intel_sdvo_get_modes(struct drm_connector *connector)
|
||||
|
|
|
@ -100,6 +100,9 @@ struct intel_sdvo_preferred_input_timing_args {
|
|||
u16 clock;
|
||||
u16 width;
|
||||
u16 height;
|
||||
u8 interlace:1;
|
||||
u8 scaled:1;
|
||||
u8 pad:6;
|
||||
} __attribute__((packed));
|
||||
|
||||
/* I2C registers for SDVO */
|
||||
|
|
|
@ -1570,33 +1570,49 @@ intel_tv_set_property(struct drm_connector *connector, struct drm_property *prop
|
|||
struct drm_device *dev = connector->dev;
|
||||
struct intel_output *intel_output = to_intel_output(connector);
|
||||
struct intel_tv_priv *tv_priv = intel_output->dev_priv;
|
||||
struct drm_encoder *encoder = &intel_output->enc;
|
||||
struct drm_crtc *crtc = encoder->crtc;
|
||||
int ret = 0;
|
||||
bool changed = false;
|
||||
|
||||
ret = drm_connector_property_set_value(connector, property, val);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
if (property == dev->mode_config.tv_left_margin_property)
|
||||
if (property == dev->mode_config.tv_left_margin_property &&
|
||||
tv_priv->margin[TV_MARGIN_LEFT] != val) {
|
||||
tv_priv->margin[TV_MARGIN_LEFT] = val;
|
||||
else if (property == dev->mode_config.tv_right_margin_property)
|
||||
changed = true;
|
||||
} else if (property == dev->mode_config.tv_right_margin_property &&
|
||||
tv_priv->margin[TV_MARGIN_RIGHT] != val) {
|
||||
tv_priv->margin[TV_MARGIN_RIGHT] = val;
|
||||
else if (property == dev->mode_config.tv_top_margin_property)
|
||||
changed = true;
|
||||
} else if (property == dev->mode_config.tv_top_margin_property &&
|
||||
tv_priv->margin[TV_MARGIN_TOP] != val) {
|
||||
tv_priv->margin[TV_MARGIN_TOP] = val;
|
||||
else if (property == dev->mode_config.tv_bottom_margin_property)
|
||||
changed = true;
|
||||
} else if (property == dev->mode_config.tv_bottom_margin_property &&
|
||||
tv_priv->margin[TV_MARGIN_BOTTOM] != val) {
|
||||
tv_priv->margin[TV_MARGIN_BOTTOM] = val;
|
||||
else if (property == dev->mode_config.tv_mode_property) {
|
||||
changed = true;
|
||||
} else if (property == dev->mode_config.tv_mode_property) {
|
||||
if (val >= NUM_TV_MODES) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
if (!strcmp(tv_priv->tv_format, tv_modes[val].name))
|
||||
goto out;
|
||||
|
||||
tv_priv->tv_format = tv_modes[val].name;
|
||||
intel_tv_mode_set(&intel_output->enc, NULL, NULL);
|
||||
changed = true;
|
||||
} else {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
intel_tv_mode_set(&intel_output->enc, NULL, NULL);
|
||||
if (changed && crtc)
|
||||
drm_crtc_helper_set_mode(crtc, &crtc->mode, crtc->x,
|
||||
crtc->y, crtc->fb);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue