Merge intel drm-intel-next branch
Merge remote branch 'anholt/drm-intel-next' of ../anholt-2.6 into drm-next Conflicts: drivers/gpu/drm/i915/intel_display.c drivers/gpu/drm/i915/intel_drv.h drivers/gpu/drm/i915/intel_sdvo.c
Esse commit está contido em:
@@ -4,10 +4,10 @@
|
||||
|
||||
ccflags-y := -Iinclude/drm
|
||||
i915-y := i915_drv.o i915_dma.o i915_irq.o i915_mem.o \
|
||||
i915_debugfs.o \
|
||||
i915_suspend.o \
|
||||
i915_gem.o \
|
||||
i915_gem_debug.o \
|
||||
i915_gem_debugfs.o \
|
||||
i915_gem_tiling.o \
|
||||
intel_display.o \
|
||||
intel_crt.o \
|
||||
|
@@ -158,16 +158,37 @@ static int i915_interrupt_info(struct seq_file *m, void *data)
|
||||
struct drm_device *dev = node->minor->dev;
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
|
||||
seq_printf(m, "Interrupt enable: %08x\n",
|
||||
I915_READ(IER));
|
||||
seq_printf(m, "Interrupt identity: %08x\n",
|
||||
I915_READ(IIR));
|
||||
seq_printf(m, "Interrupt mask: %08x\n",
|
||||
I915_READ(IMR));
|
||||
seq_printf(m, "Pipe A stat: %08x\n",
|
||||
I915_READ(PIPEASTAT));
|
||||
seq_printf(m, "Pipe B stat: %08x\n",
|
||||
I915_READ(PIPEBSTAT));
|
||||
if (!IS_IGDNG(dev)) {
|
||||
seq_printf(m, "Interrupt enable: %08x\n",
|
||||
I915_READ(IER));
|
||||
seq_printf(m, "Interrupt identity: %08x\n",
|
||||
I915_READ(IIR));
|
||||
seq_printf(m, "Interrupt mask: %08x\n",
|
||||
I915_READ(IMR));
|
||||
seq_printf(m, "Pipe A stat: %08x\n",
|
||||
I915_READ(PIPEASTAT));
|
||||
seq_printf(m, "Pipe B stat: %08x\n",
|
||||
I915_READ(PIPEBSTAT));
|
||||
} else {
|
||||
seq_printf(m, "North Display Interrupt enable: %08x\n",
|
||||
I915_READ(DEIER));
|
||||
seq_printf(m, "North Display Interrupt identity: %08x\n",
|
||||
I915_READ(DEIIR));
|
||||
seq_printf(m, "North Display Interrupt mask: %08x\n",
|
||||
I915_READ(DEIMR));
|
||||
seq_printf(m, "South Display Interrupt enable: %08x\n",
|
||||
I915_READ(SDEIER));
|
||||
seq_printf(m, "South Display Interrupt identity: %08x\n",
|
||||
I915_READ(SDEIIR));
|
||||
seq_printf(m, "South Display Interrupt mask: %08x\n",
|
||||
I915_READ(SDEIMR));
|
||||
seq_printf(m, "Graphics Interrupt enable: %08x\n",
|
||||
I915_READ(GTIER));
|
||||
seq_printf(m, "Graphics Interrupt identity: %08x\n",
|
||||
I915_READ(GTIIR));
|
||||
seq_printf(m, "Graphics Interrupt mask: %08x\n",
|
||||
I915_READ(GTIMR));
|
||||
}
|
||||
seq_printf(m, "Interrupts received: %d\n",
|
||||
atomic_read(&dev_priv->irq_received));
|
||||
if (dev_priv->hw_status_page != NULL) {
|
||||
@@ -312,15 +333,13 @@ static int i915_ringbuffer_info(struct seq_file *m, void *data)
|
||||
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;
|
||||
unsigned int head, tail, mask;
|
||||
unsigned int head, tail;
|
||||
|
||||
head = I915_READ(PRB0_HEAD) & HEAD_ADDR;
|
||||
tail = I915_READ(PRB0_TAIL) & TAIL_ADDR;
|
||||
mask = dev_priv->ring.tail_mask;
|
||||
|
||||
seq_printf(m, "RingHead : %08x\n", head);
|
||||
seq_printf(m, "RingTail : %08x\n", tail);
|
||||
seq_printf(m, "RingMask : %08x\n", mask);
|
||||
seq_printf(m, "RingSize : %08lx\n", dev_priv->ring.Size);
|
||||
seq_printf(m, "Acthd : %08x\n", I915_READ(IS_I965G(dev) ? ACTHD_I965 : ACTHD));
|
||||
|
||||
@@ -363,7 +382,37 @@ out:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct drm_info_list i915_gem_debugfs_list[] = {
|
||||
static int i915_registers_info(struct seq_file *m, void *data) {
|
||||
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;
|
||||
uint32_t reg;
|
||||
|
||||
#define DUMP_RANGE(start, end) \
|
||||
for (reg=start; reg < end; reg += 4) \
|
||||
seq_printf(m, "%08x\t%08x\n", reg, I915_READ(reg));
|
||||
|
||||
DUMP_RANGE(0x00000, 0x00fff); /* VGA registers */
|
||||
DUMP_RANGE(0x02000, 0x02fff); /* instruction, memory, interrupt control registers */
|
||||
DUMP_RANGE(0x03000, 0x031ff); /* FENCE and PPGTT control registers */
|
||||
DUMP_RANGE(0x03200, 0x03fff); /* frame buffer compression registers */
|
||||
DUMP_RANGE(0x05000, 0x05fff); /* I/O control registers */
|
||||
DUMP_RANGE(0x06000, 0x06fff); /* clock control registers */
|
||||
DUMP_RANGE(0x07000, 0x07fff); /* 3D internal debug registers */
|
||||
DUMP_RANGE(0x07400, 0x088ff); /* GPE debug registers */
|
||||
DUMP_RANGE(0x0a000, 0x0afff); /* display palette registers */
|
||||
DUMP_RANGE(0x10000, 0x13fff); /* MMIO MCHBAR */
|
||||
DUMP_RANGE(0x30000, 0x3ffff); /* overlay registers */
|
||||
DUMP_RANGE(0x60000, 0x6ffff); /* display engine pipeline registers */
|
||||
DUMP_RANGE(0x70000, 0x72fff); /* display and cursor registers */
|
||||
DUMP_RANGE(0x73000, 0x73fff); /* performance counters */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static struct drm_info_list i915_debugfs_list[] = {
|
||||
{"i915_regs", i915_registers_info, 0},
|
||||
{"i915_gem_active", i915_gem_object_list_info, 0, (void *) ACTIVE_LIST},
|
||||
{"i915_gem_flushing", i915_gem_object_list_info, 0, (void *) FLUSHING_LIST},
|
||||
{"i915_gem_inactive", i915_gem_object_list_info, 0, (void *) INACTIVE_LIST},
|
||||
@@ -377,19 +426,19 @@ static struct drm_info_list i915_gem_debugfs_list[] = {
|
||||
{"i915_batchbuffers", i915_batchbuffer_info, 0},
|
||||
{"i915_error_state", i915_error_state, 0},
|
||||
};
|
||||
#define I915_GEM_DEBUGFS_ENTRIES ARRAY_SIZE(i915_gem_debugfs_list)
|
||||
#define I915_DEBUGFS_ENTRIES ARRAY_SIZE(i915_debugfs_list)
|
||||
|
||||
int i915_gem_debugfs_init(struct drm_minor *minor)
|
||||
int i915_debugfs_init(struct drm_minor *minor)
|
||||
{
|
||||
return drm_debugfs_create_files(i915_gem_debugfs_list,
|
||||
I915_GEM_DEBUGFS_ENTRIES,
|
||||
return drm_debugfs_create_files(i915_debugfs_list,
|
||||
I915_DEBUGFS_ENTRIES,
|
||||
minor->debugfs_root, minor);
|
||||
}
|
||||
|
||||
void i915_gem_debugfs_cleanup(struct drm_minor *minor)
|
||||
void i915_debugfs_cleanup(struct drm_minor *minor)
|
||||
{
|
||||
drm_debugfs_remove_files(i915_gem_debugfs_list,
|
||||
I915_GEM_DEBUGFS_ENTRIES, minor);
|
||||
drm_debugfs_remove_files(i915_debugfs_list,
|
||||
I915_DEBUGFS_ENTRIES, minor);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_DEBUG_FS */
|
@@ -79,6 +79,34 @@ int i915_wait_ring(struct drm_device * dev, int n, const char *caller)
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
/* As a ringbuffer is only allowed to wrap between instructions, fill
|
||||
* the tail with NOOPs.
|
||||
*/
|
||||
int i915_wrap_ring(struct drm_device *dev)
|
||||
{
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
volatile unsigned int *virt;
|
||||
int rem;
|
||||
|
||||
rem = dev_priv->ring.Size - dev_priv->ring.tail;
|
||||
if (dev_priv->ring.space < rem) {
|
||||
int ret = i915_wait_ring(dev, rem, __func__);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
dev_priv->ring.space -= rem;
|
||||
|
||||
virt = (unsigned int *)
|
||||
(dev_priv->ring.virtual_start + dev_priv->ring.tail);
|
||||
rem /= 4;
|
||||
while (rem--)
|
||||
*virt++ = MI_NOOP;
|
||||
|
||||
dev_priv->ring.tail = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up the hardware status page for devices that need a physical address
|
||||
* in the register.
|
||||
@@ -198,7 +226,6 @@ static int i915_initialize(struct drm_device * dev, drm_i915_init_t * init)
|
||||
}
|
||||
|
||||
dev_priv->ring.Size = init->ring_size;
|
||||
dev_priv->ring.tail_mask = dev_priv->ring.Size - 1;
|
||||
|
||||
dev_priv->ring.map.offset = init->ring_start;
|
||||
dev_priv->ring.map.size = init->ring_size;
|
||||
|
@@ -37,12 +37,15 @@
|
||||
#include <linux/console.h>
|
||||
#include "drm_crtc_helper.h"
|
||||
|
||||
static unsigned int i915_modeset = -1;
|
||||
static int i915_modeset = -1;
|
||||
module_param_named(modeset, i915_modeset, int, 0400);
|
||||
|
||||
unsigned int i915_fbpercrtc = 0;
|
||||
module_param_named(fbpercrtc, i915_fbpercrtc, int, 0400);
|
||||
|
||||
unsigned int i915_powersave = 1;
|
||||
module_param_named(powersave, i915_powersave, int, 0400);
|
||||
|
||||
static struct drm_driver driver;
|
||||
|
||||
static struct pci_device_id pciidlist[] = {
|
||||
@@ -188,8 +191,8 @@ static struct drm_driver driver = {
|
||||
.master_create = i915_master_create,
|
||||
.master_destroy = i915_master_destroy,
|
||||
#if defined(CONFIG_DEBUG_FS)
|
||||
.debugfs_init = i915_gem_debugfs_init,
|
||||
.debugfs_cleanup = i915_gem_debugfs_cleanup,
|
||||
.debugfs_init = i915_debugfs_init,
|
||||
.debugfs_cleanup = i915_debugfs_cleanup,
|
||||
#endif
|
||||
.gem_init_object = i915_gem_init_object,
|
||||
.gem_free_object = i915_gem_free_object,
|
||||
|
@@ -85,7 +85,6 @@ struct drm_i915_gem_phys_object {
|
||||
};
|
||||
|
||||
typedef struct _drm_i915_ring_buffer {
|
||||
int tail_mask;
|
||||
unsigned long Size;
|
||||
u8 *virtual_start;
|
||||
int head;
|
||||
@@ -222,6 +221,7 @@ typedef struct drm_i915_private {
|
||||
unsigned int edp_support:1;
|
||||
int lvds_ssc_freq;
|
||||
|
||||
int crt_ddc_bus; /* -1 = unknown, else GPIO to use for CRT DDC */
|
||||
struct drm_i915_fence_reg fence_regs[16]; /* assume 965 */
|
||||
int fence_reg_start; /* 4 if userland hasn't ioctl'd us yet */
|
||||
int num_fence_regs; /* 8 on pre-965, 16 otherwise */
|
||||
@@ -310,7 +310,7 @@ typedef struct drm_i915_private {
|
||||
u32 saveIMR;
|
||||
u32 saveCACHE_MODE_0;
|
||||
u32 saveD_STATE;
|
||||
u32 saveCG_2D_DIS;
|
||||
u32 saveDSPCLK_GATE_D;
|
||||
u32 saveMI_ARB_STATE;
|
||||
u32 saveSWF0[16];
|
||||
u32 saveSWF1[16];
|
||||
@@ -384,6 +384,9 @@ typedef struct drm_i915_private {
|
||||
*/
|
||||
struct list_head inactive_list;
|
||||
|
||||
/** LRU list of objects with fence regs on them. */
|
||||
struct list_head fence_list;
|
||||
|
||||
/**
|
||||
* List of breadcrumbs associated with GPU requests currently
|
||||
* outstanding.
|
||||
@@ -439,6 +442,14 @@ typedef struct drm_i915_private {
|
||||
struct drm_i915_gem_phys_object *phys_objs[I915_MAX_PHYS_OBJECT];
|
||||
} mm;
|
||||
struct sdvo_device_mapping sdvo_mappings[2];
|
||||
|
||||
/* Reclocking support */
|
||||
bool render_reclock_avail;
|
||||
bool lvds_downclock_avail;
|
||||
struct work_struct idle_work;
|
||||
struct timer_list idle_timer;
|
||||
bool busy;
|
||||
u16 orig_clock;
|
||||
} drm_i915_private_t;
|
||||
|
||||
/** driver private structure attached to each drm_gem_object */
|
||||
@@ -451,6 +462,9 @@ struct drm_i915_gem_object {
|
||||
/** This object's place on the active/flushing/inactive lists */
|
||||
struct list_head list;
|
||||
|
||||
/** This object's place on the fenced object LRU */
|
||||
struct list_head fence_list;
|
||||
|
||||
/**
|
||||
* This is set if the object is on the active or flushing lists
|
||||
* (has pending rendering), and is not set if it's on inactive (ready
|
||||
@@ -568,6 +582,7 @@ enum intel_chip_family {
|
||||
extern struct drm_ioctl_desc i915_ioctls[];
|
||||
extern int i915_max_ioctl;
|
||||
extern unsigned int i915_fbpercrtc;
|
||||
extern unsigned int i915_powersave;
|
||||
|
||||
extern int i915_master_create(struct drm_device *dev, struct drm_master *master);
|
||||
extern void i915_master_destroy(struct drm_device *dev, struct drm_master *master);
|
||||
@@ -723,8 +738,8 @@ void i915_gem_dump_object(struct drm_gem_object *obj, int len,
|
||||
void i915_dump_lru(struct drm_device *dev, const char *where);
|
||||
|
||||
/* i915_debugfs.c */
|
||||
int i915_gem_debugfs_init(struct drm_minor *minor);
|
||||
void i915_gem_debugfs_cleanup(struct drm_minor *minor);
|
||||
int i915_debugfs_init(struct drm_minor *minor);
|
||||
void i915_debugfs_cleanup(struct drm_minor *minor);
|
||||
|
||||
/* i915_suspend.c */
|
||||
extern int i915_save_state(struct drm_device *dev);
|
||||
@@ -774,33 +789,32 @@ extern void intel_modeset_cleanup(struct drm_device *dev);
|
||||
|
||||
#define I915_VERBOSE 0
|
||||
|
||||
#define RING_LOCALS unsigned int outring, ringmask, outcount; \
|
||||
volatile char *virt;
|
||||
#define RING_LOCALS volatile unsigned int *ring_virt__;
|
||||
|
||||
#define BEGIN_LP_RING(n) do { \
|
||||
if (I915_VERBOSE) \
|
||||
DRM_DEBUG("BEGIN_LP_RING(%d)\n", (n)); \
|
||||
if (dev_priv->ring.space < (n)*4) \
|
||||
i915_wait_ring(dev, (n)*4, __func__); \
|
||||
outcount = 0; \
|
||||
outring = dev_priv->ring.tail; \
|
||||
ringmask = dev_priv->ring.tail_mask; \
|
||||
virt = dev_priv->ring.virtual_start; \
|
||||
#define BEGIN_LP_RING(n) do { \
|
||||
int bytes__ = 4*(n); \
|
||||
if (I915_VERBOSE) DRM_DEBUG("BEGIN_LP_RING(%d)\n", (n)); \
|
||||
/* a wrap must occur between instructions so pad beforehand */ \
|
||||
if (unlikely (dev_priv->ring.tail + bytes__ > dev_priv->ring.Size)) \
|
||||
i915_wrap_ring(dev); \
|
||||
if (unlikely (dev_priv->ring.space < bytes__)) \
|
||||
i915_wait_ring(dev, bytes__, __func__); \
|
||||
ring_virt__ = (unsigned int *) \
|
||||
(dev_priv->ring.virtual_start + dev_priv->ring.tail); \
|
||||
dev_priv->ring.tail += bytes__; \
|
||||
dev_priv->ring.tail &= dev_priv->ring.Size - 1; \
|
||||
dev_priv->ring.space -= bytes__; \
|
||||
} while (0)
|
||||
|
||||
#define OUT_RING(n) do { \
|
||||
#define OUT_RING(n) do { \
|
||||
if (I915_VERBOSE) DRM_DEBUG(" OUT_RING %x\n", (int)(n)); \
|
||||
*(volatile unsigned int *)(virt + outring) = (n); \
|
||||
outcount++; \
|
||||
outring += 4; \
|
||||
outring &= ringmask; \
|
||||
*ring_virt__++ = (n); \
|
||||
} while (0)
|
||||
|
||||
#define ADVANCE_LP_RING() do { \
|
||||
if (I915_VERBOSE) DRM_DEBUG("ADVANCE_LP_RING %x\n", outring); \
|
||||
dev_priv->ring.tail = outring; \
|
||||
dev_priv->ring.space -= outcount * 4; \
|
||||
I915_WRITE(PRB0_TAIL, outring); \
|
||||
if (I915_VERBOSE) \
|
||||
DRM_DEBUG("ADVANCE_LP_RING %x\n", dev_priv->ring.tail); \
|
||||
I915_WRITE(PRB0_TAIL, dev_priv->ring.tail); \
|
||||
} while(0)
|
||||
|
||||
/**
|
||||
@@ -823,6 +837,7 @@ extern void intel_modeset_cleanup(struct drm_device *dev);
|
||||
#define I915_GEM_HWS_INDEX 0x20
|
||||
#define I915_BREADCRUMB_INDEX 0x21
|
||||
|
||||
extern int i915_wrap_ring(struct drm_device * dev);
|
||||
extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller);
|
||||
|
||||
#define IS_I830(dev) ((dev)->pci_device == 0x3577)
|
||||
@@ -896,6 +911,9 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller);
|
||||
/* dsparb controlled by hw only */
|
||||
#define DSPARB_HWCONTROL(dev) (IS_G4X(dev) || IS_IGDNG(dev))
|
||||
|
||||
#define HAS_FW_BLC(dev) (IS_I9XX(dev) || IS_G4X(dev) || IS_IGDNG(dev))
|
||||
#define HAS_PIPE_CXSR(dev) (IS_G4X(dev) || IS_IGDNG(dev))
|
||||
|
||||
#define PRIMARY_RINGBUFFER_SIZE (128*1024)
|
||||
|
||||
#endif
|
||||
|
@@ -29,6 +29,7 @@
|
||||
#include "drm.h"
|
||||
#include "i915_drm.h"
|
||||
#include "i915_drv.h"
|
||||
#include "intel_drv.h"
|
||||
#include <linux/swap.h>
|
||||
#include <linux/pci.h>
|
||||
|
||||
@@ -979,8 +980,10 @@ int
|
||||
i915_gem_set_domain_ioctl(struct drm_device *dev, void *data,
|
||||
struct drm_file *file_priv)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct drm_i915_gem_set_domain *args = data;
|
||||
struct drm_gem_object *obj;
|
||||
struct drm_i915_gem_object *obj_priv;
|
||||
uint32_t read_domains = args->read_domains;
|
||||
uint32_t write_domain = args->write_domain;
|
||||
int ret;
|
||||
@@ -1004,8 +1007,12 @@ i915_gem_set_domain_ioctl(struct drm_device *dev, void *data,
|
||||
obj = drm_gem_object_lookup(dev, file_priv, args->handle);
|
||||
if (obj == NULL)
|
||||
return -EBADF;
|
||||
obj_priv = obj->driver_private;
|
||||
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
|
||||
intel_mark_busy(dev, obj);
|
||||
|
||||
#if WATCH_BUF
|
||||
DRM_INFO("set_domain_ioctl %p(%zd), %08x %08x\n",
|
||||
obj, obj->size, read_domains, write_domain);
|
||||
@@ -1013,6 +1020,14 @@ i915_gem_set_domain_ioctl(struct drm_device *dev, void *data,
|
||||
if (read_domains & I915_GEM_DOMAIN_GTT) {
|
||||
ret = i915_gem_object_set_to_gtt_domain(obj, write_domain != 0);
|
||||
|
||||
/* Update the LRU on the fence for the CPU access that's
|
||||
* about to occur.
|
||||
*/
|
||||
if (obj_priv->fence_reg != I915_FENCE_REG_NONE) {
|
||||
list_move_tail(&obj_priv->fence_list,
|
||||
&dev_priv->mm.fence_list);
|
||||
}
|
||||
|
||||
/* Silently promote "you're not bound, there was nothing to do"
|
||||
* to success, since the client was just asking us to
|
||||
* make sure everything was done.
|
||||
@@ -1156,8 +1171,7 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
|
||||
}
|
||||
|
||||
/* Need a new fence register? */
|
||||
if (obj_priv->fence_reg == I915_FENCE_REG_NONE &&
|
||||
obj_priv->tiling_mode != I915_TILING_NONE) {
|
||||
if (obj_priv->tiling_mode != I915_TILING_NONE) {
|
||||
ret = i915_gem_object_get_fence_reg(obj);
|
||||
if (ret) {
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
@@ -2209,6 +2223,12 @@ i915_gem_object_get_fence_reg(struct drm_gem_object *obj)
|
||||
struct drm_i915_gem_object *old_obj_priv = NULL;
|
||||
int i, ret, avail;
|
||||
|
||||
/* Just update our place in the LRU if our fence is getting used. */
|
||||
if (obj_priv->fence_reg != I915_FENCE_REG_NONE) {
|
||||
list_move_tail(&obj_priv->fence_list, &dev_priv->mm.fence_list);
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (obj_priv->tiling_mode) {
|
||||
case I915_TILING_NONE:
|
||||
WARN(1, "allocating a fence for non-tiled object?\n");
|
||||
@@ -2230,7 +2250,6 @@ i915_gem_object_get_fence_reg(struct drm_gem_object *obj)
|
||||
}
|
||||
|
||||
/* First try to find a free reg */
|
||||
try_again:
|
||||
avail = 0;
|
||||
for (i = dev_priv->fence_reg_start; i < dev_priv->num_fence_regs; i++) {
|
||||
reg = &dev_priv->fence_regs[i];
|
||||
@@ -2244,63 +2263,62 @@ 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;
|
||||
struct drm_gem_object *old_obj = NULL;
|
||||
|
||||
if (avail == 0)
|
||||
return -ENOSPC;
|
||||
|
||||
for (i = dev_priv->fence_reg_start;
|
||||
i < dev_priv->num_fence_regs; i++) {
|
||||
uint32_t this_seqno;
|
||||
|
||||
reg = &dev_priv->fence_regs[i];
|
||||
old_obj_priv = reg->obj->driver_private;
|
||||
list_for_each_entry(old_obj_priv, &dev_priv->mm.fence_list,
|
||||
fence_list) {
|
||||
old_obj = old_obj_priv->obj;
|
||||
|
||||
if (old_obj_priv->pin_count)
|
||||
continue;
|
||||
|
||||
/* Take a reference, as otherwise the wait_rendering
|
||||
* below may cause the object to get freed out from
|
||||
* under us.
|
||||
*/
|
||||
drm_gem_object_reference(old_obj);
|
||||
|
||||
/* i915 uses fences for GPU access to tiled buffers */
|
||||
if (IS_I965G(dev) || !old_obj_priv->active)
|
||||
break;
|
||||
|
||||
/* find the seqno of the first available fence */
|
||||
this_seqno = old_obj_priv->last_rendering_seqno;
|
||||
if (this_seqno != 0 &&
|
||||
reg->obj->write_domain == 0 &&
|
||||
i915_seqno_passed(seqno, this_seqno))
|
||||
seqno = this_seqno;
|
||||
}
|
||||
|
||||
/*
|
||||
* Now things get ugly... we have to wait for one of the
|
||||
* objects to finish before trying again.
|
||||
*/
|
||||
if (i == dev_priv->num_fence_regs) {
|
||||
if (seqno == dev_priv->mm.next_gem_seqno) {
|
||||
i915_gem_flush(dev,
|
||||
I915_GEM_GPU_DOMAINS,
|
||||
I915_GEM_GPU_DOMAINS);
|
||||
seqno = i915_add_request(dev, NULL,
|
||||
I915_GEM_GPU_DOMAINS);
|
||||
if (seqno == 0)
|
||||
return -ENOMEM;
|
||||
/* This brings the object to the head of the LRU if it
|
||||
* had been written to. The only way this should
|
||||
* result in us waiting longer than the expected
|
||||
* optimal amount of time is if there was a
|
||||
* fence-using buffer later that was read-only.
|
||||
*/
|
||||
i915_gem_object_flush_gpu_write_domain(old_obj);
|
||||
ret = i915_gem_object_wait_rendering(old_obj);
|
||||
if (ret != 0) {
|
||||
drm_gem_object_unreference(old_obj);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = i915_wait_request(dev, seqno);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto try_again;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Zap this virtual mapping so we can set up a fence again
|
||||
* for this object next time we need it.
|
||||
*/
|
||||
i915_gem_release_mmap(reg->obj);
|
||||
i915_gem_release_mmap(old_obj);
|
||||
|
||||
i = old_obj_priv->fence_reg;
|
||||
reg = &dev_priv->fence_regs[i];
|
||||
|
||||
old_obj_priv->fence_reg = I915_FENCE_REG_NONE;
|
||||
list_del_init(&old_obj_priv->fence_list);
|
||||
|
||||
drm_gem_object_unreference(old_obj);
|
||||
}
|
||||
|
||||
obj_priv->fence_reg = i;
|
||||
list_add_tail(&obj_priv->fence_list, &dev_priv->mm.fence_list);
|
||||
|
||||
reg->obj = obj;
|
||||
|
||||
if (IS_I965G(dev))
|
||||
@@ -2343,6 +2361,7 @@ i915_gem_clear_fence_reg(struct drm_gem_object *obj)
|
||||
|
||||
dev_priv->fence_regs[obj_priv->fence_reg].obj = NULL;
|
||||
obj_priv->fence_reg = I915_FENCE_REG_NONE;
|
||||
list_del_init(&obj_priv->fence_list);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2762,6 +2781,8 @@ i915_gem_object_set_to_gpu_domain(struct drm_gem_object *obj)
|
||||
BUG_ON(obj->pending_read_domains & I915_GEM_DOMAIN_CPU);
|
||||
BUG_ON(obj->pending_write_domain == I915_GEM_DOMAIN_CPU);
|
||||
|
||||
intel_mark_busy(dev, obj);
|
||||
|
||||
#if WATCH_BUF
|
||||
DRM_INFO("%s: object %p read %08x -> %08x write %08x -> %08x\n",
|
||||
__func__, obj,
|
||||
@@ -3596,9 +3617,7 @@ i915_gem_object_pin(struct drm_gem_object *obj, uint32_t alignment)
|
||||
* Pre-965 chips need a fence register set up in order to
|
||||
* properly handle tiled surfaces.
|
||||
*/
|
||||
if (!IS_I965G(dev) &&
|
||||
obj_priv->fence_reg == I915_FENCE_REG_NONE &&
|
||||
obj_priv->tiling_mode != I915_TILING_NONE) {
|
||||
if (!IS_I965G(dev) && obj_priv->tiling_mode != I915_TILING_NONE) {
|
||||
ret = i915_gem_object_get_fence_reg(obj);
|
||||
if (ret != 0) {
|
||||
if (ret != -EBUSY && ret != -ERESTARTSYS)
|
||||
@@ -3807,6 +3826,7 @@ int i915_gem_init_object(struct drm_gem_object *obj)
|
||||
obj_priv->obj = obj;
|
||||
obj_priv->fence_reg = I915_FENCE_REG_NONE;
|
||||
INIT_LIST_HEAD(&obj_priv->list);
|
||||
INIT_LIST_HEAD(&obj_priv->fence_list);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -4080,7 +4100,6 @@ i915_gem_init_ringbuffer(struct drm_device *dev)
|
||||
|
||||
/* Set up the kernel mapping for the ring. */
|
||||
ring->Size = obj->size;
|
||||
ring->tail_mask = obj->size - 1;
|
||||
|
||||
ring->map.offset = dev->agp->base + obj_priv->gtt_offset;
|
||||
ring->map.size = obj->size;
|
||||
@@ -4254,6 +4273,7 @@ i915_gem_load(struct drm_device *dev)
|
||||
INIT_LIST_HEAD(&dev_priv->mm.flushing_list);
|
||||
INIT_LIST_HEAD(&dev_priv->mm.inactive_list);
|
||||
INIT_LIST_HEAD(&dev_priv->mm.request_list);
|
||||
INIT_LIST_HEAD(&dev_priv->mm.fence_list);
|
||||
INIT_DELAYED_WORK(&dev_priv->mm.retire_work,
|
||||
i915_gem_retire_work_handler);
|
||||
dev_priv->mm.next_gem_seqno = 1;
|
||||
|
@@ -234,7 +234,13 @@ i915_gem_detect_bit_6_swizzle(struct drm_device *dev)
|
||||
uint32_t swizzle_y = I915_BIT_6_SWIZZLE_UNKNOWN;
|
||||
bool need_disable;
|
||||
|
||||
if (!IS_I9XX(dev)) {
|
||||
if (IS_IGDNG(dev)) {
|
||||
/* On IGDNG whatever DRAM config, GPU always do
|
||||
* same swizzling setup.
|
||||
*/
|
||||
swizzle_x = I915_BIT_6_SWIZZLE_9_10;
|
||||
swizzle_y = I915_BIT_6_SWIZZLE_9;
|
||||
} else if (!IS_I9XX(dev)) {
|
||||
/* As far as we know, the 865 doesn't have these bit 6
|
||||
* swizzling issues.
|
||||
*/
|
||||
@@ -317,13 +323,6 @@ i915_gem_detect_bit_6_swizzle(struct drm_device *dev)
|
||||
}
|
||||
}
|
||||
|
||||
/* FIXME: check with memory config on IGDNG */
|
||||
if (IS_IGDNG(dev)) {
|
||||
DRM_ERROR("disable tiling on IGDNG...\n");
|
||||
swizzle_x = I915_BIT_6_SWIZZLE_UNKNOWN;
|
||||
swizzle_y = I915_BIT_6_SWIZZLE_UNKNOWN;
|
||||
}
|
||||
|
||||
dev_priv->mm.bit_6_swizzle_x = swizzle_x;
|
||||
dev_priv->mm.bit_6_swizzle_y = swizzle_y;
|
||||
}
|
||||
|
@@ -565,6 +565,27 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
|
||||
|
||||
I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status);
|
||||
I915_READ(PORT_HOTPLUG_STAT);
|
||||
|
||||
/* EOS interrupts occurs */
|
||||
if (IS_IGD(dev) &&
|
||||
(hotplug_status & CRT_EOS_INT_STATUS)) {
|
||||
u32 temp;
|
||||
|
||||
DRM_DEBUG("EOS interrupt occurs\n");
|
||||
/* status is already cleared */
|
||||
temp = I915_READ(ADPA);
|
||||
temp &= ~ADPA_DAC_ENABLE;
|
||||
I915_WRITE(ADPA, temp);
|
||||
|
||||
temp = I915_READ(PORT_HOTPLUG_EN);
|
||||
temp &= ~CRT_EOS_INT_EN;
|
||||
I915_WRITE(PORT_HOTPLUG_EN, temp);
|
||||
|
||||
temp = I915_READ(PORT_HOTPLUG_STAT);
|
||||
if (temp & CRT_EOS_INT_STATUS)
|
||||
I915_WRITE(PORT_HOTPLUG_STAT,
|
||||
CRT_EOS_INT_STATUS);
|
||||
}
|
||||
}
|
||||
|
||||
I915_WRITE(IIR, iir);
|
||||
|
@@ -55,7 +55,7 @@
|
||||
/* PCI config space */
|
||||
|
||||
#define HPLLCC 0xc0 /* 855 only */
|
||||
#define GC_CLOCK_CONTROL_MASK (3 << 0)
|
||||
#define GC_CLOCK_CONTROL_MASK (0xf << 0)
|
||||
#define GC_CLOCK_133_200 (0 << 0)
|
||||
#define GC_CLOCK_100_200 (1 << 0)
|
||||
#define GC_CLOCK_100_133 (2 << 0)
|
||||
@@ -65,6 +65,25 @@
|
||||
#define GC_DISPLAY_CLOCK_190_200_MHZ (0 << 4)
|
||||
#define GC_DISPLAY_CLOCK_333_MHZ (4 << 4)
|
||||
#define GC_DISPLAY_CLOCK_MASK (7 << 4)
|
||||
#define GM45_GC_RENDER_CLOCK_MASK (0xf << 0)
|
||||
#define GM45_GC_RENDER_CLOCK_266_MHZ (8 << 0)
|
||||
#define GM45_GC_RENDER_CLOCK_320_MHZ (9 << 0)
|
||||
#define GM45_GC_RENDER_CLOCK_400_MHZ (0xb << 0)
|
||||
#define GM45_GC_RENDER_CLOCK_533_MHZ (0xc << 0)
|
||||
#define I965_GC_RENDER_CLOCK_MASK (0xf << 0)
|
||||
#define I965_GC_RENDER_CLOCK_267_MHZ (2 << 0)
|
||||
#define I965_GC_RENDER_CLOCK_333_MHZ (3 << 0)
|
||||
#define I965_GC_RENDER_CLOCK_444_MHZ (4 << 0)
|
||||
#define I965_GC_RENDER_CLOCK_533_MHZ (5 << 0)
|
||||
#define I945_GC_RENDER_CLOCK_MASK (7 << 0)
|
||||
#define I945_GC_RENDER_CLOCK_166_MHZ (0 << 0)
|
||||
#define I945_GC_RENDER_CLOCK_200_MHZ (1 << 0)
|
||||
#define I945_GC_RENDER_CLOCK_250_MHZ (3 << 0)
|
||||
#define I945_GC_RENDER_CLOCK_400_MHZ (5 << 0)
|
||||
#define I915_GC_RENDER_CLOCK_MASK (7 << 0)
|
||||
#define I915_GC_RENDER_CLOCK_166_MHZ (0 << 0)
|
||||
#define I915_GC_RENDER_CLOCK_200_MHZ (1 << 0)
|
||||
#define I915_GC_RENDER_CLOCK_333_MHZ (4 << 0)
|
||||
#define LBB 0xf4
|
||||
|
||||
/* VGA stuff */
|
||||
@@ -553,9 +572,118 @@
|
||||
#define DPLLA_TEST_M_BYPASS (1 << 2)
|
||||
#define DPLLA_INPUT_BUFFER_ENABLE (1 << 0)
|
||||
#define D_STATE 0x6104
|
||||
#define CG_2D_DIS 0x6200
|
||||
#define DPCUNIT_CLOCK_GATE_DISABLE (1 << 24)
|
||||
#define CG_3D_DIS 0x6204
|
||||
#define DSTATE_PLL_D3_OFF (1<<3)
|
||||
#define DSTATE_GFX_CLOCK_GATING (1<<1)
|
||||
#define DSTATE_DOT_CLOCK_GATING (1<<0)
|
||||
#define DSPCLK_GATE_D 0x6200
|
||||
# define DPUNIT_B_CLOCK_GATE_DISABLE (1 << 30) /* 965 */
|
||||
# define VSUNIT_CLOCK_GATE_DISABLE (1 << 29) /* 965 */
|
||||
# define VRHUNIT_CLOCK_GATE_DISABLE (1 << 28) /* 965 */
|
||||
# define VRDUNIT_CLOCK_GATE_DISABLE (1 << 27) /* 965 */
|
||||
# define AUDUNIT_CLOCK_GATE_DISABLE (1 << 26) /* 965 */
|
||||
# define DPUNIT_A_CLOCK_GATE_DISABLE (1 << 25) /* 965 */
|
||||
# define DPCUNIT_CLOCK_GATE_DISABLE (1 << 24) /* 965 */
|
||||
# define TVRUNIT_CLOCK_GATE_DISABLE (1 << 23) /* 915-945 */
|
||||
# define TVCUNIT_CLOCK_GATE_DISABLE (1 << 22) /* 915-945 */
|
||||
# define TVFUNIT_CLOCK_GATE_DISABLE (1 << 21) /* 915-945 */
|
||||
# define TVEUNIT_CLOCK_GATE_DISABLE (1 << 20) /* 915-945 */
|
||||
# define DVSUNIT_CLOCK_GATE_DISABLE (1 << 19) /* 915-945 */
|
||||
# define DSSUNIT_CLOCK_GATE_DISABLE (1 << 18) /* 915-945 */
|
||||
# define DDBUNIT_CLOCK_GATE_DISABLE (1 << 17) /* 915-945 */
|
||||
# define DPRUNIT_CLOCK_GATE_DISABLE (1 << 16) /* 915-945 */
|
||||
# define DPFUNIT_CLOCK_GATE_DISABLE (1 << 15) /* 915-945 */
|
||||
# define DPBMUNIT_CLOCK_GATE_DISABLE (1 << 14) /* 915-945 */
|
||||
# define DPLSUNIT_CLOCK_GATE_DISABLE (1 << 13) /* 915-945 */
|
||||
# define DPLUNIT_CLOCK_GATE_DISABLE (1 << 12) /* 915-945 */
|
||||
# define DPOUNIT_CLOCK_GATE_DISABLE (1 << 11)
|
||||
# define DPBUNIT_CLOCK_GATE_DISABLE (1 << 10)
|
||||
# define DCUNIT_CLOCK_GATE_DISABLE (1 << 9)
|
||||
# define DPUNIT_CLOCK_GATE_DISABLE (1 << 8)
|
||||
# define VRUNIT_CLOCK_GATE_DISABLE (1 << 7) /* 915+: reserved */
|
||||
# define OVHUNIT_CLOCK_GATE_DISABLE (1 << 6) /* 830-865 */
|
||||
# define DPIOUNIT_CLOCK_GATE_DISABLE (1 << 6) /* 915-945 */
|
||||
# define OVFUNIT_CLOCK_GATE_DISABLE (1 << 5)
|
||||
# define OVBUNIT_CLOCK_GATE_DISABLE (1 << 4)
|
||||
/**
|
||||
* This bit must be set on the 830 to prevent hangs when turning off the
|
||||
* overlay scaler.
|
||||
*/
|
||||
# define OVRUNIT_CLOCK_GATE_DISABLE (1 << 3)
|
||||
# define OVCUNIT_CLOCK_GATE_DISABLE (1 << 2)
|
||||
# define OVUUNIT_CLOCK_GATE_DISABLE (1 << 1)
|
||||
# define ZVUNIT_CLOCK_GATE_DISABLE (1 << 0) /* 830 */
|
||||
# define OVLUNIT_CLOCK_GATE_DISABLE (1 << 0) /* 845,865 */
|
||||
|
||||
#define RENCLK_GATE_D1 0x6204
|
||||
# define BLITTER_CLOCK_GATE_DISABLE (1 << 13) /* 945GM only */
|
||||
# define MPEG_CLOCK_GATE_DISABLE (1 << 12) /* 945GM only */
|
||||
# define PC_FE_CLOCK_GATE_DISABLE (1 << 11)
|
||||
# define PC_BE_CLOCK_GATE_DISABLE (1 << 10)
|
||||
# define WINDOWER_CLOCK_GATE_DISABLE (1 << 9)
|
||||
# define INTERPOLATOR_CLOCK_GATE_DISABLE (1 << 8)
|
||||
# define COLOR_CALCULATOR_CLOCK_GATE_DISABLE (1 << 7)
|
||||
# define MOTION_COMP_CLOCK_GATE_DISABLE (1 << 6)
|
||||
# define MAG_CLOCK_GATE_DISABLE (1 << 5)
|
||||
/** This bit must be unset on 855,865 */
|
||||
# define MECI_CLOCK_GATE_DISABLE (1 << 4)
|
||||
# define DCMP_CLOCK_GATE_DISABLE (1 << 3)
|
||||
# define MEC_CLOCK_GATE_DISABLE (1 << 2)
|
||||
# define MECO_CLOCK_GATE_DISABLE (1 << 1)
|
||||
/** This bit must be set on 855,865. */
|
||||
# define SV_CLOCK_GATE_DISABLE (1 << 0)
|
||||
# define I915_MPEG_CLOCK_GATE_DISABLE (1 << 16)
|
||||
# define I915_VLD_IP_PR_CLOCK_GATE_DISABLE (1 << 15)
|
||||
# define I915_MOTION_COMP_CLOCK_GATE_DISABLE (1 << 14)
|
||||
# define I915_BD_BF_CLOCK_GATE_DISABLE (1 << 13)
|
||||
# define I915_SF_SE_CLOCK_GATE_DISABLE (1 << 12)
|
||||
# define I915_WM_CLOCK_GATE_DISABLE (1 << 11)
|
||||
# define I915_IZ_CLOCK_GATE_DISABLE (1 << 10)
|
||||
# define I915_PI_CLOCK_GATE_DISABLE (1 << 9)
|
||||
# define I915_DI_CLOCK_GATE_DISABLE (1 << 8)
|
||||
# define I915_SH_SV_CLOCK_GATE_DISABLE (1 << 7)
|
||||
# define I915_PL_DG_QC_FT_CLOCK_GATE_DISABLE (1 << 6)
|
||||
# define I915_SC_CLOCK_GATE_DISABLE (1 << 5)
|
||||
# define I915_FL_CLOCK_GATE_DISABLE (1 << 4)
|
||||
# define I915_DM_CLOCK_GATE_DISABLE (1 << 3)
|
||||
# define I915_PS_CLOCK_GATE_DISABLE (1 << 2)
|
||||
# define I915_CC_CLOCK_GATE_DISABLE (1 << 1)
|
||||
# define I915_BY_CLOCK_GATE_DISABLE (1 << 0)
|
||||
|
||||
# define I965_RCZ_CLOCK_GATE_DISABLE (1 << 30)
|
||||
/** This bit must always be set on 965G/965GM */
|
||||
# define I965_RCC_CLOCK_GATE_DISABLE (1 << 29)
|
||||
# define I965_RCPB_CLOCK_GATE_DISABLE (1 << 28)
|
||||
# define I965_DAP_CLOCK_GATE_DISABLE (1 << 27)
|
||||
# define I965_ROC_CLOCK_GATE_DISABLE (1 << 26)
|
||||
# define I965_GW_CLOCK_GATE_DISABLE (1 << 25)
|
||||
# define I965_TD_CLOCK_GATE_DISABLE (1 << 24)
|
||||
/** This bit must always be set on 965G */
|
||||
# define I965_ISC_CLOCK_GATE_DISABLE (1 << 23)
|
||||
# define I965_IC_CLOCK_GATE_DISABLE (1 << 22)
|
||||
# define I965_EU_CLOCK_GATE_DISABLE (1 << 21)
|
||||
# define I965_IF_CLOCK_GATE_DISABLE (1 << 20)
|
||||
# define I965_TC_CLOCK_GATE_DISABLE (1 << 19)
|
||||
# define I965_SO_CLOCK_GATE_DISABLE (1 << 17)
|
||||
# define I965_FBC_CLOCK_GATE_DISABLE (1 << 16)
|
||||
# define I965_MARI_CLOCK_GATE_DISABLE (1 << 15)
|
||||
# define I965_MASF_CLOCK_GATE_DISABLE (1 << 14)
|
||||
# define I965_MAWB_CLOCK_GATE_DISABLE (1 << 13)
|
||||
# define I965_EM_CLOCK_GATE_DISABLE (1 << 12)
|
||||
# define I965_UC_CLOCK_GATE_DISABLE (1 << 11)
|
||||
# define I965_SI_CLOCK_GATE_DISABLE (1 << 6)
|
||||
# define I965_MT_CLOCK_GATE_DISABLE (1 << 5)
|
||||
# define I965_PL_CLOCK_GATE_DISABLE (1 << 4)
|
||||
# define I965_DG_CLOCK_GATE_DISABLE (1 << 3)
|
||||
# define I965_QC_CLOCK_GATE_DISABLE (1 << 2)
|
||||
# define I965_FT_CLOCK_GATE_DISABLE (1 << 1)
|
||||
# define I965_DM_CLOCK_GATE_DISABLE (1 << 0)
|
||||
|
||||
#define RENCLK_GATE_D2 0x6208
|
||||
#define VF_UNIT_CLOCK_GATE_DISABLE (1 << 9)
|
||||
#define GS_UNIT_CLOCK_GATE_DISABLE (1 << 7)
|
||||
#define CL_UNIT_CLOCK_GATE_DISABLE (1 << 6)
|
||||
#define RAMCLK_GATE_D 0x6210 /* CRL only */
|
||||
#define DEUC 0x6214 /* CRL only */
|
||||
|
||||
/*
|
||||
* Palette regs
|
||||
@@ -683,6 +811,7 @@
|
||||
#define SDVOB_HOTPLUG_INT_EN (1 << 26)
|
||||
#define SDVOC_HOTPLUG_INT_EN (1 << 25)
|
||||
#define TV_HOTPLUG_INT_EN (1 << 18)
|
||||
#define CRT_EOS_INT_EN (1 << 10)
|
||||
#define CRT_HOTPLUG_INT_EN (1 << 9)
|
||||
#define CRT_HOTPLUG_FORCE_DETECT (1 << 3)
|
||||
#define CRT_HOTPLUG_ACTIVATION_PERIOD_32 (0 << 8)
|
||||
@@ -717,6 +846,7 @@
|
||||
#define DPC_HOTPLUG_INT_STATUS (1 << 28)
|
||||
#define HDMID_HOTPLUG_INT_STATUS (1 << 27)
|
||||
#define DPD_HOTPLUG_INT_STATUS (1 << 27)
|
||||
#define CRT_EOS_INT_STATUS (1 << 12)
|
||||
#define CRT_HOTPLUG_INT_STATUS (1 << 11)
|
||||
#define TV_HOTPLUG_INT_STATUS (1 << 10)
|
||||
#define CRT_HOTPLUG_MONITOR_MASK (3 << 8)
|
||||
@@ -1586,6 +1716,7 @@
|
||||
#define PIPECONF_PROGRESSIVE (0 << 21)
|
||||
#define PIPECONF_INTERLACE_W_FIELD_INDICATION (6 << 21)
|
||||
#define PIPECONF_INTERLACE_FIELD_0_ONLY (7 << 21)
|
||||
#define PIPECONF_CXSR_DOWNCLOCK (1<<16)
|
||||
#define PIPEASTAT 0x70024
|
||||
#define PIPE_FIFO_UNDERRUN_STATUS (1UL<<31)
|
||||
#define PIPE_CRC_ERROR_ENABLE (1UL<<29)
|
||||
@@ -1733,6 +1864,7 @@
|
||||
#define DISPPLANE_NO_LINE_DOUBLE 0
|
||||
#define DISPPLANE_STEREO_POLARITY_FIRST 0
|
||||
#define DISPPLANE_STEREO_POLARITY_SECOND (1<<18)
|
||||
#define DISPPLANE_TRICKLE_FEED_DISABLE (1<<14) /* IGDNG */
|
||||
#define DISPPLANE_TILED (1<<10)
|
||||
#define DSPAADDR 0x70184
|
||||
#define DSPASTRIDE 0x70188
|
||||
@@ -1913,6 +2045,9 @@
|
||||
#define GTIIR 0x44018
|
||||
#define GTIER 0x4401c
|
||||
|
||||
#define DISP_ARB_CTL 0x45000
|
||||
#define DISP_TILE_SURFACE_SWIZZLING (1<<13)
|
||||
|
||||
/* PCH */
|
||||
|
||||
/* south display engine interrupt */
|
||||
|
@@ -461,7 +461,7 @@ int i915_save_state(struct drm_device *dev)
|
||||
|
||||
/* Clock gating state */
|
||||
dev_priv->saveD_STATE = I915_READ(D_STATE);
|
||||
dev_priv->saveCG_2D_DIS = I915_READ(CG_2D_DIS);
|
||||
dev_priv->saveDSPCLK_GATE_D = I915_READ(DSPCLK_GATE_D);
|
||||
|
||||
/* Cache mode state */
|
||||
dev_priv->saveCACHE_MODE_0 = I915_READ(CACHE_MODE_0);
|
||||
@@ -588,7 +588,7 @@ int i915_restore_state(struct drm_device *dev)
|
||||
|
||||
/* Clock gating state */
|
||||
I915_WRITE (D_STATE, dev_priv->saveD_STATE);
|
||||
I915_WRITE (CG_2D_DIS, dev_priv->saveCG_2D_DIS);
|
||||
I915_WRITE (DSPCLK_GATE_D, dev_priv->saveDSPCLK_GATE_D);
|
||||
|
||||
/* Cache mode state */
|
||||
I915_WRITE (CACHE_MODE_0, dev_priv->saveCACHE_MODE_0 | 0xffff0000);
|
||||
|
@@ -59,6 +59,16 @@ find_section(struct bdb_header *bdb, int section_id)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static u16
|
||||
get_blocksize(void *p)
|
||||
{
|
||||
u16 *block_ptr, block_size;
|
||||
|
||||
block_ptr = (u16 *)((char *)p - 2);
|
||||
block_size = *block_ptr;
|
||||
return block_size;
|
||||
}
|
||||
|
||||
static void
|
||||
fill_detail_timing_data(struct drm_display_mode *panel_fixed_mode,
|
||||
struct lvds_dvo_timing *dvo_timing)
|
||||
@@ -214,6 +224,41 @@ parse_general_features(struct drm_i915_private *dev_priv,
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
parse_general_definitions(struct drm_i915_private *dev_priv,
|
||||
struct bdb_header *bdb)
|
||||
{
|
||||
struct bdb_general_definitions *general;
|
||||
const int crt_bus_map_table[] = {
|
||||
GPIOB,
|
||||
GPIOA,
|
||||
GPIOC,
|
||||
GPIOD,
|
||||
GPIOE,
|
||||
GPIOF,
|
||||
};
|
||||
|
||||
/* Set sensible defaults in case we can't find the general block
|
||||
or it is the wrong chipset */
|
||||
dev_priv->crt_ddc_bus = -1;
|
||||
|
||||
general = find_section(bdb, BDB_GENERAL_DEFINITIONS);
|
||||
if (general) {
|
||||
u16 block_size = get_blocksize(general);
|
||||
if (block_size >= sizeof(*general)) {
|
||||
int bus_pin = general->crt_ddc_gmbus_pin;
|
||||
DRM_DEBUG("crt_ddc_bus_pin: %d\n", bus_pin);
|
||||
if ((bus_pin >= 1) && (bus_pin <= 6)) {
|
||||
dev_priv->crt_ddc_bus =
|
||||
crt_bus_map_table[bus_pin-1];
|
||||
}
|
||||
} else {
|
||||
DRM_DEBUG("BDB_GD too small (%d). Invalid.\n",
|
||||
block_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
parse_sdvo_device_mapping(struct drm_i915_private *dev_priv,
|
||||
struct bdb_header *bdb)
|
||||
@@ -222,7 +267,7 @@ parse_sdvo_device_mapping(struct drm_i915_private *dev_priv,
|
||||
struct bdb_general_definitions *p_defs;
|
||||
struct child_device_config *p_child;
|
||||
int i, child_device_num, count;
|
||||
u16 block_size, *block_ptr;
|
||||
u16 block_size;
|
||||
|
||||
p_defs = find_section(bdb, BDB_GENERAL_DEFINITIONS);
|
||||
if (!p_defs) {
|
||||
@@ -240,8 +285,7 @@ parse_sdvo_device_mapping(struct drm_i915_private *dev_priv,
|
||||
return;
|
||||
}
|
||||
/* get the block size of general definitions */
|
||||
block_ptr = (u16 *)((char *)p_defs - 2);
|
||||
block_size = *block_ptr;
|
||||
block_size = get_blocksize(p_defs);
|
||||
/* get the number of child device */
|
||||
child_device_num = (block_size - sizeof(*p_defs)) /
|
||||
sizeof(*p_child);
|
||||
@@ -311,8 +355,14 @@ parse_driver_features(struct drm_i915_private *dev_priv,
|
||||
}
|
||||
|
||||
driver = find_section(bdb, BDB_DRIVER_FEATURES);
|
||||
if (driver && driver->lvds_config == BDB_DRIVER_FEATURE_EDP)
|
||||
if (!driver)
|
||||
return;
|
||||
|
||||
if (driver->lvds_config == BDB_DRIVER_FEATURE_EDP)
|
||||
dev_priv->edp_support = 1;
|
||||
|
||||
if (driver->dual_frequency)
|
||||
dev_priv->render_reclock_avail = true;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -362,6 +412,7 @@ intel_init_bios(struct drm_device *dev)
|
||||
|
||||
/* Grab useful general definitions */
|
||||
parse_general_features(dev_priv, bdb);
|
||||
parse_general_definitions(dev_priv, bdb);
|
||||
parse_lfp_panel_data(dev_priv, bdb);
|
||||
parse_sdvo_panel_data(dev_priv, bdb);
|
||||
parse_sdvo_device_mapping(dev_priv, bdb);
|
||||
|
@@ -64,6 +64,34 @@ static void intel_crt_dpms(struct drm_encoder *encoder, int mode)
|
||||
}
|
||||
|
||||
I915_WRITE(reg, temp);
|
||||
|
||||
if (IS_IGD(dev)) {
|
||||
if (mode == DRM_MODE_DPMS_OFF) {
|
||||
/* turn off DAC */
|
||||
temp = I915_READ(PORT_HOTPLUG_EN);
|
||||
temp &= ~CRT_EOS_INT_EN;
|
||||
I915_WRITE(PORT_HOTPLUG_EN, temp);
|
||||
|
||||
temp = I915_READ(PORT_HOTPLUG_STAT);
|
||||
if (temp & CRT_EOS_INT_STATUS)
|
||||
I915_WRITE(PORT_HOTPLUG_STAT,
|
||||
CRT_EOS_INT_STATUS);
|
||||
} else {
|
||||
/* turn on DAC. EOS interrupt must be enabled after DAC
|
||||
* is enabled, so it sounds not good to enable it in
|
||||
* i915_driver_irq_postinstall()
|
||||
* wait 12.5ms after DAC is enabled
|
||||
*/
|
||||
msleep(13);
|
||||
temp = I915_READ(PORT_HOTPLUG_STAT);
|
||||
if (temp & CRT_EOS_INT_STATUS)
|
||||
I915_WRITE(PORT_HOTPLUG_STAT,
|
||||
CRT_EOS_INT_STATUS);
|
||||
temp = I915_READ(PORT_HOTPLUG_EN);
|
||||
temp |= CRT_EOS_INT_EN;
|
||||
I915_WRITE(PORT_HOTPLUG_EN, temp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int intel_crt_mode_valid(struct drm_connector *connector,
|
||||
@@ -508,6 +536,7 @@ void intel_crt_init(struct drm_device *dev)
|
||||
{
|
||||
struct drm_connector *connector;
|
||||
struct intel_output *intel_output;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
u32 i2c_reg;
|
||||
|
||||
intel_output = kzalloc(sizeof(struct intel_output), GFP_KERNEL);
|
||||
@@ -527,8 +556,12 @@ void intel_crt_init(struct drm_device *dev)
|
||||
/* Set up the DDC bus. */
|
||||
if (IS_IGDNG(dev))
|
||||
i2c_reg = PCH_GPIOA;
|
||||
else
|
||||
else {
|
||||
i2c_reg = GPIOA;
|
||||
/* Use VBT information for CRT DDC if available */
|
||||
if (dev_priv->crt_ddc_bus != -1)
|
||||
i2c_reg = dev_priv->crt_ddc_bus;
|
||||
}
|
||||
intel_output->ddc_bus = intel_i2c_create(dev, i2c_reg, "CRTDDC_A");
|
||||
if (!intel_output->ddc_bus) {
|
||||
dev_printk(KERN_ERR, &dev->pdev->dev, "DDC bus registration "
|
||||
@@ -537,6 +570,10 @@ void intel_crt_init(struct drm_device *dev)
|
||||
}
|
||||
|
||||
intel_output->type = INTEL_OUTPUT_ANALOG;
|
||||
intel_output->clone_mask = (1 << INTEL_SDVO_NON_TV_CLONE_BIT) |
|
||||
(1 << INTEL_ANALOG_CLONE_BIT) |
|
||||
(1 << INTEL_SDVO_LVDS_CLONE_BIT);
|
||||
intel_output->crtc_mask = (1 << 0) | (1 << 1);
|
||||
connector->interlace_allowed = 0;
|
||||
connector->doublescan_allowed = 0;
|
||||
|
||||
|
@@ -38,6 +38,7 @@
|
||||
|
||||
bool intel_pipe_has_type (struct drm_crtc *crtc, int type);
|
||||
static void intel_update_watermarks(struct drm_device *dev);
|
||||
static void intel_increase_pllclock(struct drm_crtc *crtc, bool schedule);
|
||||
|
||||
typedef struct {
|
||||
/* given values */
|
||||
@@ -67,6 +68,8 @@ struct intel_limit {
|
||||
intel_p2_t p2;
|
||||
bool (* find_pll)(const intel_limit_t *, struct drm_crtc *,
|
||||
int, int, intel_clock_t *);
|
||||
bool (* find_reduced_pll)(const intel_limit_t *, struct drm_crtc *,
|
||||
int, int, intel_clock_t *);
|
||||
};
|
||||
|
||||
#define I8XX_DOT_MIN 25000
|
||||
@@ -261,6 +264,9 @@ static bool
|
||||
intel_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
|
||||
int target, int refclk, intel_clock_t *best_clock);
|
||||
static bool
|
||||
intel_find_best_reduced_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
|
||||
int target, int refclk, intel_clock_t *best_clock);
|
||||
static bool
|
||||
intel_g4x_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
|
||||
int target, int refclk, intel_clock_t *best_clock);
|
||||
static bool
|
||||
@@ -286,6 +292,7 @@ static const intel_limit_t intel_limits_i8xx_dvo = {
|
||||
.p2 = { .dot_limit = I8XX_P2_SLOW_LIMIT,
|
||||
.p2_slow = I8XX_P2_SLOW, .p2_fast = I8XX_P2_FAST },
|
||||
.find_pll = intel_find_best_PLL,
|
||||
.find_reduced_pll = intel_find_best_reduced_PLL,
|
||||
};
|
||||
|
||||
static const intel_limit_t intel_limits_i8xx_lvds = {
|
||||
@@ -300,6 +307,7 @@ static const intel_limit_t intel_limits_i8xx_lvds = {
|
||||
.p2 = { .dot_limit = I8XX_P2_SLOW_LIMIT,
|
||||
.p2_slow = I8XX_P2_LVDS_SLOW, .p2_fast = I8XX_P2_LVDS_FAST },
|
||||
.find_pll = intel_find_best_PLL,
|
||||
.find_reduced_pll = intel_find_best_reduced_PLL,
|
||||
};
|
||||
|
||||
static const intel_limit_t intel_limits_i9xx_sdvo = {
|
||||
@@ -314,6 +322,7 @@ static const intel_limit_t intel_limits_i9xx_sdvo = {
|
||||
.p2 = { .dot_limit = I9XX_P2_SDVO_DAC_SLOW_LIMIT,
|
||||
.p2_slow = I9XX_P2_SDVO_DAC_SLOW, .p2_fast = I9XX_P2_SDVO_DAC_FAST },
|
||||
.find_pll = intel_find_best_PLL,
|
||||
.find_reduced_pll = intel_find_best_reduced_PLL,
|
||||
};
|
||||
|
||||
static const intel_limit_t intel_limits_i9xx_lvds = {
|
||||
@@ -331,6 +340,7 @@ static const intel_limit_t intel_limits_i9xx_lvds = {
|
||||
.p2 = { .dot_limit = I9XX_P2_LVDS_SLOW_LIMIT,
|
||||
.p2_slow = I9XX_P2_LVDS_SLOW, .p2_fast = I9XX_P2_LVDS_FAST },
|
||||
.find_pll = intel_find_best_PLL,
|
||||
.find_reduced_pll = intel_find_best_reduced_PLL,
|
||||
};
|
||||
|
||||
/* below parameter and function is for G4X Chipset Family*/
|
||||
@@ -348,6 +358,7 @@ static const intel_limit_t intel_limits_g4x_sdvo = {
|
||||
.p2_fast = G4X_P2_SDVO_FAST
|
||||
},
|
||||
.find_pll = intel_g4x_find_best_PLL,
|
||||
.find_reduced_pll = intel_g4x_find_best_PLL,
|
||||
};
|
||||
|
||||
static const intel_limit_t intel_limits_g4x_hdmi = {
|
||||
@@ -364,6 +375,7 @@ static const intel_limit_t intel_limits_g4x_hdmi = {
|
||||
.p2_fast = G4X_P2_HDMI_DAC_FAST
|
||||
},
|
||||
.find_pll = intel_g4x_find_best_PLL,
|
||||
.find_reduced_pll = intel_g4x_find_best_PLL,
|
||||
};
|
||||
|
||||
static const intel_limit_t intel_limits_g4x_single_channel_lvds = {
|
||||
@@ -388,6 +400,7 @@ static const intel_limit_t intel_limits_g4x_single_channel_lvds = {
|
||||
.p2_fast = G4X_P2_SINGLE_CHANNEL_LVDS_FAST
|
||||
},
|
||||
.find_pll = intel_g4x_find_best_PLL,
|
||||
.find_reduced_pll = intel_g4x_find_best_PLL,
|
||||
};
|
||||
|
||||
static const intel_limit_t intel_limits_g4x_dual_channel_lvds = {
|
||||
@@ -412,6 +425,7 @@ static const intel_limit_t intel_limits_g4x_dual_channel_lvds = {
|
||||
.p2_fast = G4X_P2_DUAL_CHANNEL_LVDS_FAST
|
||||
},
|
||||
.find_pll = intel_g4x_find_best_PLL,
|
||||
.find_reduced_pll = intel_g4x_find_best_PLL,
|
||||
};
|
||||
|
||||
static const intel_limit_t intel_limits_g4x_display_port = {
|
||||
@@ -449,6 +463,7 @@ static const intel_limit_t intel_limits_igd_sdvo = {
|
||||
.p2 = { .dot_limit = I9XX_P2_SDVO_DAC_SLOW_LIMIT,
|
||||
.p2_slow = I9XX_P2_SDVO_DAC_SLOW, .p2_fast = I9XX_P2_SDVO_DAC_FAST },
|
||||
.find_pll = intel_find_best_PLL,
|
||||
.find_reduced_pll = intel_find_best_reduced_PLL,
|
||||
};
|
||||
|
||||
static const intel_limit_t intel_limits_igd_lvds = {
|
||||
@@ -464,6 +479,7 @@ static const intel_limit_t intel_limits_igd_lvds = {
|
||||
.p2 = { .dot_limit = I9XX_P2_LVDS_SLOW_LIMIT,
|
||||
.p2_slow = I9XX_P2_LVDS_SLOW, .p2_fast = I9XX_P2_LVDS_SLOW },
|
||||
.find_pll = intel_find_best_PLL,
|
||||
.find_reduced_pll = intel_find_best_reduced_PLL,
|
||||
};
|
||||
|
||||
static const intel_limit_t intel_limits_igdng_sdvo = {
|
||||
@@ -666,7 +682,7 @@ intel_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
|
||||
intel_clock_t clock;
|
||||
int err = target;
|
||||
|
||||
if (IS_I9XX(dev) && intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) &&
|
||||
if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) &&
|
||||
(I915_READ(LVDS)) != 0) {
|
||||
/*
|
||||
* For LVDS, if the panel is on, just rely on its current
|
||||
@@ -688,15 +704,16 @@ intel_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
|
||||
|
||||
memset (best_clock, 0, sizeof (*best_clock));
|
||||
|
||||
for (clock.m1 = limit->m1.min; clock.m1 <= limit->m1.max; clock.m1++) {
|
||||
for (clock.m2 = limit->m2.min; clock.m2 <= limit->m2.max; clock.m2++) {
|
||||
/* m1 is always 0 in IGD */
|
||||
if (clock.m2 >= clock.m1 && !IS_IGD(dev))
|
||||
break;
|
||||
for (clock.n = limit->n.min; clock.n <= limit->n.max;
|
||||
clock.n++) {
|
||||
for (clock.p1 = limit->p1.min;
|
||||
clock.p1 <= limit->p1.max; clock.p1++) {
|
||||
for (clock.p1 = limit->p1.max; clock.p1 >= limit->p1.min; clock.p1--) {
|
||||
for (clock.m1 = limit->m1.min; clock.m1 <= limit->m1.max;
|
||||
clock.m1++) {
|
||||
for (clock.m2 = limit->m2.min;
|
||||
clock.m2 <= limit->m2.max; clock.m2++) {
|
||||
/* m1 is always 0 in IGD */
|
||||
if (clock.m2 >= clock.m1 && !IS_IGD(dev))
|
||||
break;
|
||||
for (clock.n = limit->n.min;
|
||||
clock.n <= limit->n.max; clock.n++) {
|
||||
int this_err;
|
||||
|
||||
intel_clock(dev, refclk, &clock);
|
||||
@@ -717,6 +734,46 @@ intel_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
|
||||
return (err != target);
|
||||
}
|
||||
|
||||
|
||||
static bool
|
||||
intel_find_best_reduced_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
|
||||
int target, int refclk, intel_clock_t *best_clock)
|
||||
|
||||
{
|
||||
struct drm_device *dev = crtc->dev;
|
||||
intel_clock_t clock;
|
||||
int err = target;
|
||||
bool found = false;
|
||||
|
||||
memcpy(&clock, best_clock, sizeof(intel_clock_t));
|
||||
|
||||
for (clock.m1 = limit->m1.min; clock.m1 <= limit->m1.max; clock.m1++) {
|
||||
for (clock.m2 = limit->m2.min; clock.m2 <= limit->m2.max; clock.m2++) {
|
||||
/* m1 is always 0 in IGD */
|
||||
if (clock.m2 >= clock.m1 && !IS_IGD(dev))
|
||||
break;
|
||||
for (clock.n = limit->n.min; clock.n <= limit->n.max;
|
||||
clock.n++) {
|
||||
int this_err;
|
||||
|
||||
intel_clock(dev, refclk, &clock);
|
||||
|
||||
if (!intel_PLL_is_valid(crtc, &clock))
|
||||
continue;
|
||||
|
||||
this_err = abs(clock.dot - target);
|
||||
if (this_err < err) {
|
||||
*best_clock = clock;
|
||||
err = this_err;
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
static bool
|
||||
intel_g4x_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
|
||||
int target, int refclk, intel_clock_t *best_clock)
|
||||
@@ -747,7 +804,7 @@ intel_g4x_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
|
||||
max_n = limit->n.max;
|
||||
/* based on hardware requriment prefer smaller n to precision */
|
||||
for (clock.n = limit->n.min; clock.n <= max_n; clock.n++) {
|
||||
/* based on hardware requirment prefere larger m1,m2, p1 */
|
||||
/* based on hardware requirment prefere larger m1,m2 */
|
||||
for (clock.m1 = limit->m1.max;
|
||||
clock.m1 >= limit->m1.min; clock.m1--) {
|
||||
for (clock.m2 = limit->m2.max;
|
||||
@@ -832,15 +889,14 @@ intel_igdng_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
|
||||
|
||||
memset(best_clock, 0, sizeof(*best_clock));
|
||||
max_n = limit->n.max;
|
||||
/* based on hardware requriment prefer smaller n to precision */
|
||||
for (clock.n = limit->n.min; clock.n <= max_n; clock.n++) {
|
||||
/* based on hardware requirment prefere larger m1,m2, p1 */
|
||||
for (clock.m1 = limit->m1.max;
|
||||
clock.m1 >= limit->m1.min; clock.m1--) {
|
||||
for (clock.m2 = limit->m2.max;
|
||||
clock.m2 >= limit->m2.min; clock.m2--) {
|
||||
for (clock.p1 = limit->p1.max;
|
||||
clock.p1 >= limit->p1.min; clock.p1--) {
|
||||
for (clock.p1 = limit->p1.max; clock.p1 >= limit->p1.min; clock.p1--) {
|
||||
/* based on hardware requriment prefer smaller n to precision */
|
||||
for (clock.n = limit->n.min; clock.n <= max_n; clock.n++) {
|
||||
/* based on hardware requirment prefere larger m1,m2 */
|
||||
for (clock.m1 = limit->m1.max;
|
||||
clock.m1 >= limit->m1.min; clock.m1--) {
|
||||
for (clock.m2 = limit->m2.max;
|
||||
clock.m2 >= limit->m2.min; clock.m2--) {
|
||||
int this_err;
|
||||
|
||||
intel_clock(dev, refclk, &clock);
|
||||
@@ -1008,6 +1064,10 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
|
||||
dspcntr &= ~DISPPLANE_TILED;
|
||||
}
|
||||
|
||||
if (IS_IGDNG(dev))
|
||||
/* must disable */
|
||||
dspcntr |= DISPPLANE_TRICKLE_FEED_DISABLE;
|
||||
|
||||
I915_WRITE(dspcntr_reg, dspcntr);
|
||||
|
||||
Start = obj_priv->gtt_offset;
|
||||
@@ -1030,8 +1090,11 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
|
||||
|
||||
if (old_fb) {
|
||||
intel_fb = to_intel_framebuffer(old_fb);
|
||||
obj_priv = intel_fb->obj->driver_private;
|
||||
i915_gem_object_unpin(intel_fb->obj);
|
||||
}
|
||||
intel_increase_pllclock(crtc, true);
|
||||
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
|
||||
if (!dev->primary->master)
|
||||
@@ -1581,6 +1644,8 @@ static void intel_crtc_dpms(struct drm_crtc *crtc, int mode)
|
||||
else
|
||||
i9xx_crtc_dpms(crtc, mode);
|
||||
|
||||
intel_crtc->dpms_mode = mode;
|
||||
|
||||
if (!dev->primary->master)
|
||||
return;
|
||||
|
||||
@@ -1603,8 +1668,6 @@ static void intel_crtc_dpms(struct drm_crtc *crtc, int mode)
|
||||
DRM_ERROR("Can't update pipe %d in SAREA\n", pipe);
|
||||
break;
|
||||
}
|
||||
|
||||
intel_crtc->dpms_mode = mode;
|
||||
}
|
||||
|
||||
static void intel_crtc_prepare (struct drm_crtc *crtc)
|
||||
@@ -2005,7 +2068,21 @@ static void igd_enable_cxsr(struct drm_device *dev, unsigned long clock,
|
||||
return;
|
||||
}
|
||||
|
||||
const static int latency_ns = 3000; /* default for non-igd platforms */
|
||||
/*
|
||||
* Latency for FIFO fetches is dependent on several factors:
|
||||
* - memory configuration (speed, channels)
|
||||
* - chipset
|
||||
* - current MCH state
|
||||
* It can be fairly high in some situations, so here we assume a fairly
|
||||
* pessimal value. It's a tradeoff between extra memory fetches (if we
|
||||
* set this value too high, the FIFO will fetch frequently to stay full)
|
||||
* and power consumption (set it too low to save power and we might see
|
||||
* FIFO underruns and display "flicker").
|
||||
*
|
||||
* A value of 5us seems to be a good balance; safe for very low end
|
||||
* platforms but not overly aggressive on lower latency configs.
|
||||
*/
|
||||
const static int latency_ns = 5000;
|
||||
|
||||
static int intel_get_fifo_size(struct drm_device *dev, int plane)
|
||||
{
|
||||
@@ -2040,6 +2117,18 @@ static int intel_get_fifo_size(struct drm_device *dev, int plane)
|
||||
return size;
|
||||
}
|
||||
|
||||
static void g4x_update_wm(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
u32 fw_blc_self = I915_READ(FW_BLC_SELF);
|
||||
|
||||
if (i915_powersave)
|
||||
fw_blc_self |= FW_BLC_SELF_EN;
|
||||
else
|
||||
fw_blc_self &= ~FW_BLC_SELF_EN;
|
||||
I915_WRITE(FW_BLC_SELF, fw_blc_self);
|
||||
}
|
||||
|
||||
static void i965_update_wm(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
@@ -2091,7 +2180,8 @@ static void i9xx_update_wm(struct drm_device *dev, int planea_clock,
|
||||
cwm = 2;
|
||||
|
||||
/* Calc sr entries for one plane configs */
|
||||
if (sr_hdisplay && (!planea_clock || !planeb_clock)) {
|
||||
if (HAS_FW_BLC(dev) && sr_hdisplay &&
|
||||
(!planea_clock || !planeb_clock)) {
|
||||
/* self-refresh has much higher latency */
|
||||
const static int sr_latency_ns = 6000;
|
||||
|
||||
@@ -2106,8 +2196,7 @@ static void i9xx_update_wm(struct drm_device *dev, int planea_clock,
|
||||
srwm = total_size - sr_entries;
|
||||
if (srwm < 0)
|
||||
srwm = 1;
|
||||
if (IS_I9XX(dev))
|
||||
I915_WRITE(FW_BLC_SELF, (srwm & 0x3f));
|
||||
I915_WRITE(FW_BLC_SELF, FW_BLC_SELF_EN | (srwm & 0x3f));
|
||||
}
|
||||
|
||||
DRM_DEBUG("Setting FIFO watermarks - A: %d, B: %d, C: %d, SR %d\n",
|
||||
@@ -2181,9 +2270,6 @@ static void intel_update_watermarks(struct drm_device *dev)
|
||||
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);
|
||||
@@ -2216,7 +2302,9 @@ static void intel_update_watermarks(struct drm_device *dev)
|
||||
else if (IS_IGD(dev))
|
||||
igd_disable_cxsr(dev);
|
||||
|
||||
if (IS_I965G(dev))
|
||||
if (IS_G4X(dev))
|
||||
g4x_update_wm(dev);
|
||||
else 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,
|
||||
@@ -2250,9 +2338,9 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
|
||||
int dsppos_reg = (pipe == 0) ? DSPAPOS : DSPBPOS;
|
||||
int pipesrc_reg = (pipe == 0) ? PIPEASRC : PIPEBSRC;
|
||||
int refclk, num_outputs = 0;
|
||||
intel_clock_t clock;
|
||||
u32 dpll = 0, fp = 0, dspcntr, pipeconf;
|
||||
bool ok, is_sdvo = false, is_dvo = false;
|
||||
intel_clock_t clock, reduced_clock;
|
||||
u32 dpll = 0, fp = 0, fp2 = 0, dspcntr, pipeconf;
|
||||
bool ok, has_reduced_clock = false, is_sdvo = false, is_dvo = false;
|
||||
bool is_crt = false, is_lvds = false, is_tv = false, is_dp = false;
|
||||
bool is_edp = false;
|
||||
struct drm_mode_config *mode_config = &dev->mode_config;
|
||||
@@ -2335,6 +2423,14 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (limit->find_reduced_pll && dev_priv->lvds_downclock_avail) {
|
||||
memcpy(&reduced_clock, &clock, sizeof(intel_clock_t));
|
||||
has_reduced_clock = limit->find_reduced_pll(limit, crtc,
|
||||
(adjusted_mode->clock*3/4),
|
||||
refclk,
|
||||
&reduced_clock);
|
||||
}
|
||||
|
||||
/* SDVO TV has fixed PLL values depend on its clock range,
|
||||
this mirrors vbios setting. */
|
||||
if (is_sdvo && is_tv) {
|
||||
@@ -2380,10 +2476,17 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
|
||||
link_bw, &m_n);
|
||||
}
|
||||
|
||||
if (IS_IGD(dev))
|
||||
if (IS_IGD(dev)) {
|
||||
fp = (1 << clock.n) << 16 | clock.m1 << 8 | clock.m2;
|
||||
else
|
||||
if (has_reduced_clock)
|
||||
fp2 = (1 << reduced_clock.n) << 16 |
|
||||
reduced_clock.m1 << 8 | reduced_clock.m2;
|
||||
} else {
|
||||
fp = clock.n << 16 | clock.m1 << 8 | clock.m2;
|
||||
if (has_reduced_clock)
|
||||
fp2 = reduced_clock.n << 16 | reduced_clock.m1 << 8 |
|
||||
reduced_clock.m2;
|
||||
}
|
||||
|
||||
if (!IS_IGDNG(dev))
|
||||
dpll = DPLL_VGA_MODE_DIS;
|
||||
@@ -2396,7 +2499,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
|
||||
if (is_sdvo) {
|
||||
dpll |= DPLL_DVO_HIGH_SPEED;
|
||||
sdvo_pixel_multiply = adjusted_mode->clock / mode->clock;
|
||||
if (IS_I945G(dev) || IS_I945GM(dev))
|
||||
if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev))
|
||||
dpll |= (sdvo_pixel_multiply - 1) << SDVO_MULTIPLIER_SHIFT_HIRES;
|
||||
else if (IS_IGDNG(dev))
|
||||
dpll |= (sdvo_pixel_multiply - 1) << PLL_REF_SDVO_HDMI_MULTIPLIER_SHIFT;
|
||||
@@ -2412,6 +2515,8 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
|
||||
/* also FPA1 */
|
||||
if (IS_IGDNG(dev))
|
||||
dpll |= (1 << (clock.p1 - 1)) << DPLL_FPA1_P1_POST_DIV_SHIFT;
|
||||
if (IS_G4X(dev) && has_reduced_clock)
|
||||
dpll |= (1 << (reduced_clock.p1 - 1)) << DPLL_FPA1_P1_POST_DIV_SHIFT;
|
||||
}
|
||||
switch (clock.p2) {
|
||||
case 5:
|
||||
@@ -2559,6 +2664,22 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
|
||||
udelay(150);
|
||||
}
|
||||
|
||||
if (is_lvds && has_reduced_clock && i915_powersave) {
|
||||
I915_WRITE(fp_reg + 4, fp2);
|
||||
intel_crtc->lowfreq_avail = true;
|
||||
if (HAS_PIPE_CXSR(dev)) {
|
||||
DRM_DEBUG("enabling CxSR downclocking\n");
|
||||
pipeconf |= PIPECONF_CXSR_DOWNCLOCK;
|
||||
}
|
||||
} else {
|
||||
I915_WRITE(fp_reg + 4, fp);
|
||||
intel_crtc->lowfreq_avail = false;
|
||||
if (HAS_PIPE_CXSR(dev)) {
|
||||
DRM_DEBUG("disabling CxSR downclocking\n");
|
||||
pipeconf &= ~PIPECONF_CXSR_DOWNCLOCK;
|
||||
}
|
||||
}
|
||||
|
||||
I915_WRITE(htot_reg, (adjusted_mode->crtc_hdisplay - 1) |
|
||||
((adjusted_mode->crtc_htotal - 1) << 16));
|
||||
I915_WRITE(hblank_reg, (adjusted_mode->crtc_hblank_start - 1) |
|
||||
@@ -2602,6 +2723,12 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
|
||||
|
||||
intel_wait_for_vblank(dev);
|
||||
|
||||
if (IS_IGDNG(dev)) {
|
||||
/* enable address swizzle for tiling buffer */
|
||||
temp = I915_READ(DISP_ARB_CTL);
|
||||
I915_WRITE(DISP_ARB_CTL, temp | DISP_TILE_SURFACE_SWIZZLING);
|
||||
}
|
||||
|
||||
I915_WRITE(dspcntr_reg, dspcntr);
|
||||
|
||||
/* Flush the plane changes */
|
||||
@@ -2755,10 +2882,16 @@ static int intel_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
|
||||
struct drm_device *dev = crtc->dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
|
||||
struct intel_framebuffer *intel_fb;
|
||||
int pipe = intel_crtc->pipe;
|
||||
uint32_t temp = 0;
|
||||
uint32_t adder;
|
||||
|
||||
if (crtc->fb) {
|
||||
intel_fb = to_intel_framebuffer(crtc->fb);
|
||||
intel_mark_busy(dev, intel_fb->obj);
|
||||
}
|
||||
|
||||
if (x < 0) {
|
||||
temp |= CURSOR_POS_SIGN << CURSOR_X_SHIFT;
|
||||
x = -x;
|
||||
@@ -3056,6 +3189,315 @@ struct drm_display_mode *intel_crtc_mode_get(struct drm_device *dev,
|
||||
return mode;
|
||||
}
|
||||
|
||||
#define GPU_IDLE_TIMEOUT 500 /* ms */
|
||||
|
||||
/* When this timer fires, we've been idle for awhile */
|
||||
static void intel_gpu_idle_timer(unsigned long arg)
|
||||
{
|
||||
struct drm_device *dev = (struct drm_device *)arg;
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
|
||||
DRM_DEBUG("idle timer fired, downclocking\n");
|
||||
|
||||
dev_priv->busy = false;
|
||||
|
||||
queue_work(dev_priv->wq, &dev_priv->idle_work);
|
||||
}
|
||||
|
||||
void intel_increase_renderclock(struct drm_device *dev, bool schedule)
|
||||
{
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
|
||||
if (IS_IGDNG(dev))
|
||||
return;
|
||||
|
||||
if (!dev_priv->render_reclock_avail) {
|
||||
DRM_DEBUG("not reclocking render clock\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Restore render clock frequency to original value */
|
||||
if (IS_G4X(dev) || IS_I9XX(dev))
|
||||
pci_write_config_word(dev->pdev, GCFGC, dev_priv->orig_clock);
|
||||
else if (IS_I85X(dev))
|
||||
pci_write_config_word(dev->pdev, HPLLCC, dev_priv->orig_clock);
|
||||
DRM_DEBUG("increasing render clock frequency\n");
|
||||
|
||||
/* Schedule downclock */
|
||||
if (schedule)
|
||||
mod_timer(&dev_priv->idle_timer, jiffies +
|
||||
msecs_to_jiffies(GPU_IDLE_TIMEOUT));
|
||||
}
|
||||
|
||||
void intel_decrease_renderclock(struct drm_device *dev)
|
||||
{
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
|
||||
if (IS_IGDNG(dev))
|
||||
return;
|
||||
|
||||
if (!dev_priv->render_reclock_avail) {
|
||||
DRM_DEBUG("not reclocking render clock\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (IS_G4X(dev)) {
|
||||
u16 gcfgc;
|
||||
|
||||
/* Adjust render clock... */
|
||||
pci_read_config_word(dev->pdev, GCFGC, &gcfgc);
|
||||
|
||||
/* Down to minimum... */
|
||||
gcfgc &= ~GM45_GC_RENDER_CLOCK_MASK;
|
||||
gcfgc |= GM45_GC_RENDER_CLOCK_266_MHZ;
|
||||
|
||||
pci_write_config_word(dev->pdev, GCFGC, gcfgc);
|
||||
} else if (IS_I965G(dev)) {
|
||||
u16 gcfgc;
|
||||
|
||||
/* Adjust render clock... */
|
||||
pci_read_config_word(dev->pdev, GCFGC, &gcfgc);
|
||||
|
||||
/* Down to minimum... */
|
||||
gcfgc &= ~I965_GC_RENDER_CLOCK_MASK;
|
||||
gcfgc |= I965_GC_RENDER_CLOCK_267_MHZ;
|
||||
|
||||
pci_write_config_word(dev->pdev, GCFGC, gcfgc);
|
||||
} else if (IS_I945G(dev) || IS_I945GM(dev)) {
|
||||
u16 gcfgc;
|
||||
|
||||
/* Adjust render clock... */
|
||||
pci_read_config_word(dev->pdev, GCFGC, &gcfgc);
|
||||
|
||||
/* Down to minimum... */
|
||||
gcfgc &= ~I945_GC_RENDER_CLOCK_MASK;
|
||||
gcfgc |= I945_GC_RENDER_CLOCK_166_MHZ;
|
||||
|
||||
pci_write_config_word(dev->pdev, GCFGC, gcfgc);
|
||||
} else if (IS_I915G(dev)) {
|
||||
u16 gcfgc;
|
||||
|
||||
/* Adjust render clock... */
|
||||
pci_read_config_word(dev->pdev, GCFGC, &gcfgc);
|
||||
|
||||
/* Down to minimum... */
|
||||
gcfgc &= ~I915_GC_RENDER_CLOCK_MASK;
|
||||
gcfgc |= I915_GC_RENDER_CLOCK_166_MHZ;
|
||||
|
||||
pci_write_config_word(dev->pdev, GCFGC, gcfgc);
|
||||
} else if (IS_I85X(dev)) {
|
||||
u16 hpllcc;
|
||||
|
||||
/* Adjust render clock... */
|
||||
pci_read_config_word(dev->pdev, HPLLCC, &hpllcc);
|
||||
|
||||
/* Up to maximum... */
|
||||
hpllcc &= ~GC_CLOCK_CONTROL_MASK;
|
||||
hpllcc |= GC_CLOCK_133_200;
|
||||
|
||||
pci_write_config_word(dev->pdev, HPLLCC, hpllcc);
|
||||
}
|
||||
DRM_DEBUG("decreasing render clock frequency\n");
|
||||
}
|
||||
|
||||
/* Note that no increase function is needed for this - increase_renderclock()
|
||||
* will also rewrite these bits
|
||||
*/
|
||||
void intel_decrease_displayclock(struct drm_device *dev)
|
||||
{
|
||||
if (IS_IGDNG(dev))
|
||||
return;
|
||||
|
||||
if (IS_I945G(dev) || IS_I945GM(dev) || IS_I915G(dev) ||
|
||||
IS_I915GM(dev)) {
|
||||
u16 gcfgc;
|
||||
|
||||
/* Adjust render clock... */
|
||||
pci_read_config_word(dev->pdev, GCFGC, &gcfgc);
|
||||
|
||||
/* Down to minimum... */
|
||||
gcfgc &= ~0xf0;
|
||||
gcfgc |= 0x80;
|
||||
|
||||
pci_write_config_word(dev->pdev, GCFGC, gcfgc);
|
||||
}
|
||||
}
|
||||
|
||||
#define CRTC_IDLE_TIMEOUT 1000 /* ms */
|
||||
|
||||
static void intel_crtc_idle_timer(unsigned long arg)
|
||||
{
|
||||
struct intel_crtc *intel_crtc = (struct intel_crtc *)arg;
|
||||
struct drm_crtc *crtc = &intel_crtc->base;
|
||||
drm_i915_private_t *dev_priv = crtc->dev->dev_private;
|
||||
|
||||
DRM_DEBUG("idle timer fired, downclocking\n");
|
||||
|
||||
intel_crtc->busy = false;
|
||||
|
||||
queue_work(dev_priv->wq, &dev_priv->idle_work);
|
||||
}
|
||||
|
||||
static void intel_increase_pllclock(struct drm_crtc *crtc, bool schedule)
|
||||
{
|
||||
struct drm_device *dev = crtc->dev;
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
|
||||
int pipe = intel_crtc->pipe;
|
||||
int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B;
|
||||
int dpll = I915_READ(dpll_reg);
|
||||
|
||||
if (IS_IGDNG(dev))
|
||||
return;
|
||||
|
||||
if (!dev_priv->lvds_downclock_avail)
|
||||
return;
|
||||
|
||||
if (!HAS_PIPE_CXSR(dev) && (dpll & DISPLAY_RATE_SELECT_FPA1)) {
|
||||
DRM_DEBUG("upclocking LVDS\n");
|
||||
|
||||
/* Unlock panel regs */
|
||||
I915_WRITE(PP_CONTROL, I915_READ(PP_CONTROL) | (0xabcd << 16));
|
||||
|
||||
dpll &= ~DISPLAY_RATE_SELECT_FPA1;
|
||||
I915_WRITE(dpll_reg, dpll);
|
||||
dpll = I915_READ(dpll_reg);
|
||||
intel_wait_for_vblank(dev);
|
||||
dpll = I915_READ(dpll_reg);
|
||||
if (dpll & DISPLAY_RATE_SELECT_FPA1)
|
||||
DRM_DEBUG("failed to upclock LVDS!\n");
|
||||
|
||||
/* ...and lock them again */
|
||||
I915_WRITE(PP_CONTROL, I915_READ(PP_CONTROL) & 0x3);
|
||||
}
|
||||
|
||||
/* Schedule downclock */
|
||||
if (schedule)
|
||||
mod_timer(&intel_crtc->idle_timer, jiffies +
|
||||
msecs_to_jiffies(CRTC_IDLE_TIMEOUT));
|
||||
}
|
||||
|
||||
static void intel_decrease_pllclock(struct drm_crtc *crtc)
|
||||
{
|
||||
struct drm_device *dev = crtc->dev;
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
|
||||
int pipe = intel_crtc->pipe;
|
||||
int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B;
|
||||
int dpll = I915_READ(dpll_reg);
|
||||
|
||||
if (IS_IGDNG(dev))
|
||||
return;
|
||||
|
||||
if (!dev_priv->lvds_downclock_avail)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Since this is called by a timer, we should never get here in
|
||||
* the manual case.
|
||||
*/
|
||||
if (!HAS_PIPE_CXSR(dev) && intel_crtc->lowfreq_avail) {
|
||||
DRM_DEBUG("downclocking LVDS\n");
|
||||
|
||||
/* Unlock panel regs */
|
||||
I915_WRITE(PP_CONTROL, I915_READ(PP_CONTROL) | (0xabcd << 16));
|
||||
|
||||
dpll |= DISPLAY_RATE_SELECT_FPA1;
|
||||
I915_WRITE(dpll_reg, dpll);
|
||||
dpll = I915_READ(dpll_reg);
|
||||
intel_wait_for_vblank(dev);
|
||||
dpll = I915_READ(dpll_reg);
|
||||
if (!(dpll & DISPLAY_RATE_SELECT_FPA1))
|
||||
DRM_DEBUG("failed to downclock LVDS!\n");
|
||||
|
||||
/* ...and lock them again */
|
||||
I915_WRITE(PP_CONTROL, I915_READ(PP_CONTROL) & 0x3);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* intel_idle_update - adjust clocks for idleness
|
||||
* @work: work struct
|
||||
*
|
||||
* Either the GPU or display (or both) went idle. Check the busy status
|
||||
* here and adjust the CRTC and GPU clocks as necessary.
|
||||
*/
|
||||
static void intel_idle_update(struct work_struct *work)
|
||||
{
|
||||
drm_i915_private_t *dev_priv = container_of(work, drm_i915_private_t,
|
||||
idle_work);
|
||||
struct drm_device *dev = dev_priv->dev;
|
||||
struct drm_crtc *crtc;
|
||||
struct intel_crtc *intel_crtc;
|
||||
|
||||
if (!i915_powersave)
|
||||
return;
|
||||
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
|
||||
/* GPU isn't processing, downclock it. */
|
||||
if (!dev_priv->busy) {
|
||||
intel_decrease_renderclock(dev);
|
||||
intel_decrease_displayclock(dev);
|
||||
}
|
||||
|
||||
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
|
||||
/* Skip inactive CRTCs */
|
||||
if (!crtc->fb)
|
||||
continue;
|
||||
|
||||
intel_crtc = to_intel_crtc(crtc);
|
||||
if (!intel_crtc->busy)
|
||||
intel_decrease_pllclock(crtc);
|
||||
}
|
||||
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
}
|
||||
|
||||
/**
|
||||
* intel_mark_busy - mark the GPU and possibly the display busy
|
||||
* @dev: drm device
|
||||
* @obj: object we're operating on
|
||||
*
|
||||
* Callers can use this function to indicate that the GPU is busy processing
|
||||
* commands. If @obj matches one of the CRTC objects (i.e. it's a scanout
|
||||
* buffer), we'll also mark the display as busy, so we know to increase its
|
||||
* clock frequency.
|
||||
*/
|
||||
void intel_mark_busy(struct drm_device *dev, struct drm_gem_object *obj)
|
||||
{
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
struct drm_crtc *crtc = NULL;
|
||||
struct intel_framebuffer *intel_fb;
|
||||
struct intel_crtc *intel_crtc;
|
||||
|
||||
if (!drm_core_check_feature(dev, DRIVER_MODESET))
|
||||
return;
|
||||
|
||||
dev_priv->busy = true;
|
||||
intel_increase_renderclock(dev, true);
|
||||
|
||||
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
|
||||
if (!crtc->fb)
|
||||
continue;
|
||||
|
||||
intel_crtc = to_intel_crtc(crtc);
|
||||
intel_fb = to_intel_framebuffer(crtc->fb);
|
||||
if (intel_fb->obj == obj) {
|
||||
if (!intel_crtc->busy) {
|
||||
/* Non-busy -> busy, upclock */
|
||||
intel_increase_pllclock(crtc, true);
|
||||
intel_crtc->busy = true;
|
||||
} else {
|
||||
/* Busy -> busy, put off timer */
|
||||
mod_timer(&intel_crtc->idle_timer, jiffies +
|
||||
msecs_to_jiffies(CRTC_IDLE_TIMEOUT));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void intel_crtc_destroy(struct drm_crtc *crtc)
|
||||
{
|
||||
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
|
||||
@@ -3105,6 +3547,11 @@ static void intel_crtc_init(struct drm_device *dev, int pipe)
|
||||
intel_crtc->cursor_addr = 0;
|
||||
intel_crtc->dpms_mode = DRM_MODE_DPMS_OFF;
|
||||
drm_crtc_helper_add(&intel_crtc->base, &intel_helper_funcs);
|
||||
|
||||
intel_crtc->busy = false;
|
||||
|
||||
setup_timer(&intel_crtc->idle_timer, intel_crtc_idle_timer,
|
||||
(unsigned long)intel_crtc);
|
||||
}
|
||||
|
||||
int intel_get_pipe_from_crtc_id(struct drm_device *dev, void *data,
|
||||
@@ -3112,30 +3559,26 @@ int intel_get_pipe_from_crtc_id(struct drm_device *dev, void *data,
|
||||
{
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
struct drm_i915_get_pipe_from_crtc_id *pipe_from_crtc_id = data;
|
||||
struct drm_crtc *crtc = NULL;
|
||||
int pipe = -1;
|
||||
struct drm_mode_object *drmmode_obj;
|
||||
struct intel_crtc *crtc;
|
||||
|
||||
if (!dev_priv) {
|
||||
DRM_ERROR("called with no initialization\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
|
||||
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
|
||||
if (crtc->base.id == pipe_from_crtc_id->crtc_id) {
|
||||
pipe = intel_crtc->pipe;
|
||||
break;
|
||||
}
|
||||
}
|
||||
drmmode_obj = drm_mode_object_find(dev, pipe_from_crtc_id->crtc_id,
|
||||
DRM_MODE_OBJECT_CRTC);
|
||||
|
||||
if (pipe == -1) {
|
||||
if (!drmmode_obj) {
|
||||
DRM_ERROR("no such CRTC id\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
pipe_from_crtc_id->pipe = pipe;
|
||||
crtc = to_intel_crtc(obj_to_crtc(drmmode_obj));
|
||||
pipe_from_crtc_id->pipe = crtc->pipe;
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct drm_crtc *intel_get_crtc_from_pipe(struct drm_device *dev, int pipe)
|
||||
@@ -3158,7 +3601,7 @@ static int intel_connector_clones(struct drm_device *dev, int type_mask)
|
||||
|
||||
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
|
||||
struct intel_output *intel_output = to_intel_output(connector);
|
||||
if (type_mask & (1 << intel_output->type))
|
||||
if (type_mask & intel_output->clone_mask)
|
||||
index_mask |= (1 << entry);
|
||||
entry++;
|
||||
}
|
||||
@@ -3206,30 +3649,30 @@ static void intel_setup_outputs(struct drm_device *dev)
|
||||
intel_dp_init(dev, PCH_DP_D);
|
||||
|
||||
} else if (IS_I9XX(dev)) {
|
||||
int found;
|
||||
u32 reg;
|
||||
bool found = false;
|
||||
|
||||
if (I915_READ(SDVOB) & SDVO_DETECTED) {
|
||||
found = intel_sdvo_init(dev, SDVOB);
|
||||
if (!found && SUPPORTS_INTEGRATED_HDMI(dev))
|
||||
intel_hdmi_init(dev, SDVOB);
|
||||
|
||||
if (!found && SUPPORTS_INTEGRATED_DP(dev))
|
||||
intel_dp_init(dev, DP_B);
|
||||
}
|
||||
|
||||
/* Before G4X SDVOC doesn't have its own detect register */
|
||||
if (IS_G4X(dev))
|
||||
reg = SDVOC;
|
||||
else
|
||||
reg = SDVOB;
|
||||
|
||||
if (I915_READ(reg) & SDVO_DETECTED) {
|
||||
if (I915_READ(SDVOB) & SDVO_DETECTED)
|
||||
found = intel_sdvo_init(dev, SDVOC);
|
||||
if (!found && SUPPORTS_INTEGRATED_HDMI(dev))
|
||||
|
||||
if (!found && (I915_READ(SDVOC) & SDVO_DETECTED)) {
|
||||
|
||||
if (SUPPORTS_INTEGRATED_HDMI(dev))
|
||||
intel_hdmi_init(dev, SDVOC);
|
||||
if (!found && SUPPORTS_INTEGRATED_DP(dev))
|
||||
if (SUPPORTS_INTEGRATED_DP(dev))
|
||||
intel_dp_init(dev, DP_C);
|
||||
}
|
||||
|
||||
if (SUPPORTS_INTEGRATED_DP(dev) && (I915_READ(DP_D) & DP_DETECTED))
|
||||
intel_dp_init(dev, DP_D);
|
||||
} else
|
||||
@@ -3241,51 +3684,10 @@ static void intel_setup_outputs(struct drm_device *dev)
|
||||
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
|
||||
struct intel_output *intel_output = to_intel_output(connector);
|
||||
struct drm_encoder *encoder = &intel_output->enc;
|
||||
int crtc_mask = 0, clone_mask = 0;
|
||||
|
||||
/* valid crtcs */
|
||||
switch(intel_output->type) {
|
||||
case INTEL_OUTPUT_HDMI:
|
||||
crtc_mask = ((1 << 0)|
|
||||
(1 << 1));
|
||||
clone_mask = ((1 << INTEL_OUTPUT_HDMI));
|
||||
break;
|
||||
case INTEL_OUTPUT_DVO:
|
||||
case INTEL_OUTPUT_SDVO:
|
||||
crtc_mask = ((1 << 0)|
|
||||
(1 << 1));
|
||||
clone_mask = ((1 << INTEL_OUTPUT_ANALOG) |
|
||||
(1 << INTEL_OUTPUT_DVO) |
|
||||
(1 << INTEL_OUTPUT_SDVO));
|
||||
break;
|
||||
case INTEL_OUTPUT_ANALOG:
|
||||
crtc_mask = ((1 << 0)|
|
||||
(1 << 1));
|
||||
clone_mask = ((1 << INTEL_OUTPUT_ANALOG) |
|
||||
(1 << INTEL_OUTPUT_DVO) |
|
||||
(1 << INTEL_OUTPUT_SDVO));
|
||||
break;
|
||||
case INTEL_OUTPUT_LVDS:
|
||||
crtc_mask = (1 << 1);
|
||||
clone_mask = (1 << INTEL_OUTPUT_LVDS);
|
||||
break;
|
||||
case INTEL_OUTPUT_TVOUT:
|
||||
crtc_mask = ((1 << 0) |
|
||||
(1 << 1));
|
||||
clone_mask = (1 << INTEL_OUTPUT_TVOUT);
|
||||
break;
|
||||
case INTEL_OUTPUT_DISPLAYPORT:
|
||||
crtc_mask = ((1 << 0) |
|
||||
(1 << 1));
|
||||
clone_mask = (1 << INTEL_OUTPUT_DISPLAYPORT);
|
||||
break;
|
||||
case INTEL_OUTPUT_EDP:
|
||||
crtc_mask = (1 << 1);
|
||||
clone_mask = (1 << INTEL_OUTPUT_EDP);
|
||||
break;
|
||||
}
|
||||
encoder->possible_crtcs = crtc_mask;
|
||||
encoder->possible_clones = intel_connector_clones(dev, clone_mask);
|
||||
encoder->possible_crtcs = intel_output->crtc_mask;
|
||||
encoder->possible_clones = intel_connector_clones(dev,
|
||||
intel_output->clone_mask);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3377,8 +3779,56 @@ static const struct drm_mode_config_funcs intel_mode_funcs = {
|
||||
.fb_changed = intelfb_probe,
|
||||
};
|
||||
|
||||
void intel_init_clock_gating(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
|
||||
/*
|
||||
* Disable clock gating reported to work incorrectly according to the
|
||||
* specs, but enable as much else as we can.
|
||||
*/
|
||||
if (IS_G4X(dev)) {
|
||||
uint32_t dspclk_gate;
|
||||
I915_WRITE(RENCLK_GATE_D1, 0);
|
||||
I915_WRITE(RENCLK_GATE_D2, VF_UNIT_CLOCK_GATE_DISABLE |
|
||||
GS_UNIT_CLOCK_GATE_DISABLE |
|
||||
CL_UNIT_CLOCK_GATE_DISABLE);
|
||||
I915_WRITE(RAMCLK_GATE_D, 0);
|
||||
dspclk_gate = VRHUNIT_CLOCK_GATE_DISABLE |
|
||||
OVRUNIT_CLOCK_GATE_DISABLE |
|
||||
OVCUNIT_CLOCK_GATE_DISABLE;
|
||||
if (IS_GM45(dev))
|
||||
dspclk_gate |= DSSUNIT_CLOCK_GATE_DISABLE;
|
||||
I915_WRITE(DSPCLK_GATE_D, dspclk_gate);
|
||||
} else if (IS_I965GM(dev)) {
|
||||
I915_WRITE(RENCLK_GATE_D1, I965_RCC_CLOCK_GATE_DISABLE);
|
||||
I915_WRITE(RENCLK_GATE_D2, 0);
|
||||
I915_WRITE(DSPCLK_GATE_D, 0);
|
||||
I915_WRITE(RAMCLK_GATE_D, 0);
|
||||
I915_WRITE16(DEUC, 0);
|
||||
} else if (IS_I965G(dev)) {
|
||||
I915_WRITE(RENCLK_GATE_D1, I965_RCZ_CLOCK_GATE_DISABLE |
|
||||
I965_RCC_CLOCK_GATE_DISABLE |
|
||||
I965_RCPB_CLOCK_GATE_DISABLE |
|
||||
I965_ISC_CLOCK_GATE_DISABLE |
|
||||
I965_FBC_CLOCK_GATE_DISABLE);
|
||||
I915_WRITE(RENCLK_GATE_D2, 0);
|
||||
} else if (IS_I9XX(dev)) {
|
||||
u32 dstate = I915_READ(D_STATE);
|
||||
|
||||
dstate |= DSTATE_PLL_D3_OFF | DSTATE_GFX_CLOCK_GATING |
|
||||
DSTATE_DOT_CLOCK_GATING;
|
||||
I915_WRITE(D_STATE, dstate);
|
||||
} else if (IS_I855(dev) || IS_I865G(dev)) {
|
||||
I915_WRITE(RENCLK_GATE_D1, SV_CLOCK_GATE_DISABLE);
|
||||
} else if (IS_I830(dev)) {
|
||||
I915_WRITE(DSPCLK_GATE_D, OVRUNIT_CLOCK_GATE_DISABLE);
|
||||
}
|
||||
}
|
||||
|
||||
void intel_modeset_init(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
int num_pipe;
|
||||
int i;
|
||||
|
||||
@@ -3413,15 +3863,47 @@ void intel_modeset_init(struct drm_device *dev)
|
||||
DRM_DEBUG("%d display pipe%s available.\n",
|
||||
num_pipe, num_pipe > 1 ? "s" : "");
|
||||
|
||||
if (IS_I85X(dev))
|
||||
pci_read_config_word(dev->pdev, HPLLCC, &dev_priv->orig_clock);
|
||||
else if (IS_I9XX(dev) || IS_G4X(dev))
|
||||
pci_read_config_word(dev->pdev, GCFGC, &dev_priv->orig_clock);
|
||||
|
||||
for (i = 0; i < num_pipe; i++) {
|
||||
intel_crtc_init(dev, i);
|
||||
}
|
||||
|
||||
intel_setup_outputs(dev);
|
||||
|
||||
intel_init_clock_gating(dev);
|
||||
|
||||
INIT_WORK(&dev_priv->idle_work, intel_idle_update);
|
||||
setup_timer(&dev_priv->idle_timer, intel_gpu_idle_timer,
|
||||
(unsigned long)dev);
|
||||
}
|
||||
|
||||
void intel_modeset_cleanup(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct drm_crtc *crtc;
|
||||
struct intel_crtc *intel_crtc;
|
||||
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
|
||||
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
|
||||
/* Skip inactive CRTCs */
|
||||
if (!crtc->fb)
|
||||
continue;
|
||||
|
||||
intel_crtc = to_intel_crtc(crtc);
|
||||
intel_increase_pllclock(crtc, false);
|
||||
del_timer_sync(&intel_crtc->idle_timer);
|
||||
}
|
||||
|
||||
intel_increase_renderclock(dev, false);
|
||||
del_timer_sync(&dev_priv->idle_timer);
|
||||
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
|
||||
drm_mode_config_cleanup(dev);
|
||||
}
|
||||
|
||||
|
@@ -1254,6 +1254,18 @@ intel_dp_init(struct drm_device *dev, int output_reg)
|
||||
else
|
||||
intel_output->type = INTEL_OUTPUT_DISPLAYPORT;
|
||||
|
||||
if (output_reg == DP_B)
|
||||
intel_output->clone_mask = (1 << INTEL_DP_B_CLONE_BIT);
|
||||
else if (output_reg == DP_C)
|
||||
intel_output->clone_mask = (1 << INTEL_DP_C_CLONE_BIT);
|
||||
else if (output_reg == DP_D)
|
||||
intel_output->clone_mask = (1 << INTEL_DP_D_CLONE_BIT);
|
||||
|
||||
if (IS_eDP(intel_output)) {
|
||||
intel_output->crtc_mask = (1 << 1);
|
||||
intel_output->clone_mask = (1 << INTEL_OUTPUT_EDP);
|
||||
} else
|
||||
intel_output->crtc_mask = (1 << 0) | (1 << 1);
|
||||
connector->interlace_allowed = true;
|
||||
connector->doublescan_allowed = 0;
|
||||
|
||||
|
@@ -57,6 +57,24 @@
|
||||
#define INTEL_OUTPUT_DISPLAYPORT 7
|
||||
#define INTEL_OUTPUT_EDP 8
|
||||
|
||||
/* Intel Pipe Clone Bit */
|
||||
#define INTEL_HDMIB_CLONE_BIT 1
|
||||
#define INTEL_HDMIC_CLONE_BIT 2
|
||||
#define INTEL_HDMID_CLONE_BIT 3
|
||||
#define INTEL_HDMIE_CLONE_BIT 4
|
||||
#define INTEL_HDMIF_CLONE_BIT 5
|
||||
#define INTEL_SDVO_NON_TV_CLONE_BIT 6
|
||||
#define INTEL_SDVO_TV_CLONE_BIT 7
|
||||
#define INTEL_SDVO_LVDS_CLONE_BIT 8
|
||||
#define INTEL_ANALOG_CLONE_BIT 9
|
||||
#define INTEL_TV_CLONE_BIT 10
|
||||
#define INTEL_DP_B_CLONE_BIT 11
|
||||
#define INTEL_DP_C_CLONE_BIT 12
|
||||
#define INTEL_DP_D_CLONE_BIT 13
|
||||
#define INTEL_LVDS_CLONE_BIT 14
|
||||
#define INTEL_DVO_TMDS_CLONE_BIT 15
|
||||
#define INTEL_DVO_LVDS_CLONE_BIT 16
|
||||
|
||||
#define INTEL_DVO_CHIP_NONE 0
|
||||
#define INTEL_DVO_CHIP_LVDS 1
|
||||
#define INTEL_DVO_CHIP_TMDS 2
|
||||
@@ -86,6 +104,8 @@ struct intel_output {
|
||||
bool needs_tv_clock;
|
||||
void *dev_priv;
|
||||
void (*hot_plug)(struct intel_output *);
|
||||
int crtc_mask;
|
||||
int clone_mask;
|
||||
};
|
||||
|
||||
struct intel_crtc {
|
||||
@@ -96,6 +116,9 @@ struct intel_crtc {
|
||||
uint32_t cursor_addr;
|
||||
u8 lut_r[256], lut_g[256], lut_b[256];
|
||||
int dpms_mode;
|
||||
bool busy; /* is scanout buffer being updated frequently? */
|
||||
struct timer_list idle_timer;
|
||||
bool lowfreq_avail;
|
||||
};
|
||||
|
||||
#define to_intel_crtc(x) container_of(x, struct intel_crtc, base)
|
||||
@@ -114,6 +137,7 @@ extern void intel_hdmi_init(struct drm_device *dev, int sdvox_reg);
|
||||
extern bool intel_sdvo_init(struct drm_device *dev, int output_device);
|
||||
extern void intel_dvo_init(struct drm_device *dev);
|
||||
extern void intel_tv_init(struct drm_device *dev);
|
||||
extern void intel_mark_busy(struct drm_device *dev, struct drm_gem_object *obj);
|
||||
extern void intel_lvds_init(struct drm_device *dev);
|
||||
extern void intel_dp_init(struct drm_device *dev, int dp_reg);
|
||||
void
|
||||
|
@@ -435,14 +435,20 @@ void intel_dvo_init(struct drm_device *dev)
|
||||
continue;
|
||||
|
||||
intel_output->type = INTEL_OUTPUT_DVO;
|
||||
intel_output->crtc_mask = (1 << 0) | (1 << 1);
|
||||
switch (dvo->type) {
|
||||
case INTEL_DVO_CHIP_TMDS:
|
||||
intel_output->clone_mask =
|
||||
(1 << INTEL_DVO_TMDS_CLONE_BIT) |
|
||||
(1 << INTEL_ANALOG_CLONE_BIT);
|
||||
drm_connector_init(dev, connector,
|
||||
&intel_dvo_connector_funcs,
|
||||
DRM_MODE_CONNECTOR_DVII);
|
||||
encoder_type = DRM_MODE_ENCODER_TMDS;
|
||||
break;
|
||||
case INTEL_DVO_CHIP_LVDS:
|
||||
intel_output->clone_mask =
|
||||
(1 << INTEL_DVO_LVDS_CLONE_BIT);
|
||||
drm_connector_init(dev, connector,
|
||||
&intel_dvo_connector_funcs,
|
||||
DRM_MODE_CONNECTOR_LVDS);
|
||||
|
@@ -230,22 +230,28 @@ void intel_hdmi_init(struct drm_device *dev, int sdvox_reg)
|
||||
|
||||
connector->interlace_allowed = 0;
|
||||
connector->doublescan_allowed = 0;
|
||||
intel_output->crtc_mask = (1 << 0) | (1 << 1);
|
||||
|
||||
/* Set up the DDC bus. */
|
||||
if (sdvox_reg == SDVOB)
|
||||
if (sdvox_reg == SDVOB) {
|
||||
intel_output->clone_mask = (1 << INTEL_HDMIB_CLONE_BIT);
|
||||
intel_output->ddc_bus = intel_i2c_create(dev, GPIOE, "HDMIB");
|
||||
else if (sdvox_reg == SDVOC)
|
||||
} else if (sdvox_reg == SDVOC) {
|
||||
intel_output->clone_mask = (1 << INTEL_HDMIC_CLONE_BIT);
|
||||
intel_output->ddc_bus = intel_i2c_create(dev, GPIOD, "HDMIC");
|
||||
else if (sdvox_reg == HDMIB)
|
||||
} else if (sdvox_reg == HDMIB) {
|
||||
intel_output->clone_mask = (1 << INTEL_HDMID_CLONE_BIT);
|
||||
intel_output->ddc_bus = intel_i2c_create(dev, PCH_GPIOE,
|
||||
"HDMIB");
|
||||
else if (sdvox_reg == HDMIC)
|
||||
} else if (sdvox_reg == HDMIC) {
|
||||
intel_output->clone_mask = (1 << INTEL_HDMIE_CLONE_BIT);
|
||||
intel_output->ddc_bus = intel_i2c_create(dev, PCH_GPIOD,
|
||||
"HDMIC");
|
||||
else if (sdvox_reg == HDMID)
|
||||
} else if (sdvox_reg == HDMID) {
|
||||
intel_output->clone_mask = (1 << INTEL_HDMIF_CLONE_BIT);
|
||||
intel_output->ddc_bus = intel_i2c_create(dev, PCH_GPIOF,
|
||||
"HDMID");
|
||||
|
||||
}
|
||||
if (!intel_output->ddc_bus)
|
||||
goto err_connector;
|
||||
|
||||
|
@@ -42,11 +42,11 @@ void intel_i2c_quirk_set(struct drm_device *dev, bool enable)
|
||||
if (!IS_IGD(dev))
|
||||
return;
|
||||
if (enable)
|
||||
I915_WRITE(CG_2D_DIS,
|
||||
I915_READ(CG_2D_DIS) | DPCUNIT_CLOCK_GATE_DISABLE);
|
||||
I915_WRITE(DSPCLK_GATE_D,
|
||||
I915_READ(DSPCLK_GATE_D) | DPCUNIT_CLOCK_GATE_DISABLE);
|
||||
else
|
||||
I915_WRITE(CG_2D_DIS,
|
||||
I915_READ(CG_2D_DIS) & (~DPCUNIT_CLOCK_GATE_DISABLE));
|
||||
I915_WRITE(DSPCLK_GATE_D,
|
||||
I915_READ(DSPCLK_GATE_D) & (~DPCUNIT_CLOCK_GATE_DISABLE));
|
||||
}
|
||||
|
||||
/*
|
||||
|
@@ -904,6 +904,8 @@ void intel_lvds_init(struct drm_device *dev)
|
||||
drm_mode_connector_attach_encoder(&intel_output->base, &intel_output->enc);
|
||||
intel_output->type = INTEL_OUTPUT_LVDS;
|
||||
|
||||
intel_output->clone_mask = (1 << INTEL_LVDS_CLONE_BIT);
|
||||
intel_output->crtc_mask = (1 << 1);
|
||||
drm_encoder_helper_add(encoder, &intel_lvds_helper_funcs);
|
||||
drm_connector_helper_add(connector, &intel_lvds_connector_helper_funcs);
|
||||
connector->display_info.subpixel_order = SubPixelHorizontalRGB;
|
||||
|
@@ -37,6 +37,19 @@
|
||||
#include "intel_sdvo_regs.h"
|
||||
|
||||
#undef SDVO_DEBUG
|
||||
|
||||
static char *tv_format_names[] = {
|
||||
"NTSC_M" , "NTSC_J" , "NTSC_443",
|
||||
"PAL_B" , "PAL_D" , "PAL_G" ,
|
||||
"PAL_H" , "PAL_I" , "PAL_M" ,
|
||||
"PAL_N" , "PAL_NC" , "PAL_60" ,
|
||||
"SECAM_B" , "SECAM_D" , "SECAM_G" ,
|
||||
"SECAM_K" , "SECAM_K1", "SECAM_L" ,
|
||||
"SECAM_60"
|
||||
};
|
||||
|
||||
#define TV_FORMAT_NUM (sizeof(tv_format_names) / sizeof(*tv_format_names))
|
||||
|
||||
struct intel_sdvo_priv {
|
||||
u8 slave_addr;
|
||||
|
||||
@@ -70,6 +83,15 @@ struct intel_sdvo_priv {
|
||||
*/
|
||||
bool is_tv;
|
||||
|
||||
/* This is for current tv format name */
|
||||
char *tv_format_name;
|
||||
|
||||
/* This contains all current supported TV format */
|
||||
char *tv_format_supported[TV_FORMAT_NUM];
|
||||
int format_supported_num;
|
||||
struct drm_property *tv_format_property;
|
||||
struct drm_property *tv_format_name_property[TV_FORMAT_NUM];
|
||||
|
||||
/**
|
||||
* This is set if we treat the device as HDMI, instead of DVI.
|
||||
*/
|
||||
@@ -96,14 +118,6 @@ struct intel_sdvo_priv {
|
||||
*/
|
||||
struct intel_sdvo_sdtv_resolution_reply sdtv_resolutions;
|
||||
|
||||
/**
|
||||
* Current selected TV format.
|
||||
*
|
||||
* This is stored in the same structure that's passed to the device, for
|
||||
* convenience.
|
||||
*/
|
||||
struct intel_sdvo_tv_format tv_format;
|
||||
|
||||
/*
|
||||
* supported encoding mode, used to determine whether HDMI is
|
||||
* supported
|
||||
@@ -113,6 +127,9 @@ struct intel_sdvo_priv {
|
||||
/* DDC bus used by this SDVO output */
|
||||
uint8_t ddc_bus;
|
||||
|
||||
/* Mac mini hack -- use the same DDC as the analog connector */
|
||||
struct i2c_adapter *analog_ddc_bus;
|
||||
|
||||
int save_sdvo_mult;
|
||||
u16 save_active_outputs;
|
||||
struct intel_sdvo_dtd save_input_dtd_1, save_input_dtd_2;
|
||||
@@ -944,23 +961,28 @@ static void intel_sdvo_set_avi_infoframe(struct intel_output *output,
|
||||
|
||||
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_KMS("%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_KMS("%s: Failed to set TV format\n",
|
||||
SDVO_NAME(sdvo_priv));
|
||||
}
|
||||
struct intel_sdvo_tv_format format;
|
||||
struct intel_sdvo_priv *sdvo_priv = output->dev_priv;
|
||||
uint32_t format_map, i;
|
||||
uint8_t status;
|
||||
|
||||
for (i = 0; i < TV_FORMAT_NUM; i++)
|
||||
if (tv_format_names[i] == sdvo_priv->tv_format_name)
|
||||
break;
|
||||
|
||||
format_map = 1 << i;
|
||||
memset(&format, 0, sizeof(format));
|
||||
memcpy(&format, &format_map, sizeof(format_map) > sizeof(format) ?
|
||||
sizeof(format) : sizeof(format_map));
|
||||
|
||||
intel_sdvo_write_cmd(output, SDVO_CMD_SET_TV_FORMAT, &format_map,
|
||||
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,
|
||||
@@ -1457,7 +1479,7 @@ intel_sdvo_multifunc_encoder(struct intel_output *intel_output)
|
||||
(SDVO_OUTPUT_RGB0 | SDVO_OUTPUT_RGB1))
|
||||
caps++;
|
||||
if (sdvo_priv->caps.output_flags &
|
||||
(SDVO_OUTPUT_SVID0 | SDVO_OUTPUT_SVID0))
|
||||
(SDVO_OUTPUT_SVID0 | SDVO_OUTPUT_SVID1))
|
||||
caps++;
|
||||
if (sdvo_priv->caps.output_flags &
|
||||
(SDVO_OUTPUT_CVBS0 | SDVO_OUTPUT_CVBS1))
|
||||
@@ -1477,6 +1499,36 @@ intel_sdvo_multifunc_encoder(struct intel_output *intel_output)
|
||||
return (caps > 1);
|
||||
}
|
||||
|
||||
static struct drm_connector *
|
||||
intel_find_analog_connector(struct drm_device *dev)
|
||||
{
|
||||
struct drm_connector *connector;
|
||||
struct intel_output *intel_output;
|
||||
|
||||
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
|
||||
intel_output = to_intel_output(connector);
|
||||
if (intel_output->type == INTEL_OUTPUT_ANALOG)
|
||||
return connector;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
intel_analog_is_connected(struct drm_device *dev)
|
||||
{
|
||||
struct drm_connector *analog_connector;
|
||||
analog_connector = intel_find_analog_connector(dev);
|
||||
|
||||
if (!analog_connector)
|
||||
return false;
|
||||
|
||||
if (analog_connector->funcs->detect(analog_connector) ==
|
||||
connector_status_disconnected)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
enum drm_connector_status
|
||||
intel_sdvo_hdmi_sink_detect(struct drm_connector *connector, u16 response)
|
||||
{
|
||||
@@ -1487,6 +1539,15 @@ intel_sdvo_hdmi_sink_detect(struct drm_connector *connector, u16 response)
|
||||
|
||||
edid = drm_get_edid(&intel_output->base,
|
||||
intel_output->ddc_bus);
|
||||
|
||||
/* when there is no edid and no monitor is connected with VGA
|
||||
* port, try to use the CRT ddc to read the EDID for DVI-connector
|
||||
*/
|
||||
if (edid == NULL &&
|
||||
sdvo_priv->analog_ddc_bus &&
|
||||
!intel_analog_is_connected(intel_output->base.dev))
|
||||
edid = drm_get_edid(&intel_output->base,
|
||||
sdvo_priv->analog_ddc_bus);
|
||||
if (edid != NULL) {
|
||||
/* Don't report the output as connected if it's a DVI-I
|
||||
* connector with a non-digital EDID coming out.
|
||||
@@ -1515,7 +1576,8 @@ static enum drm_connector_status intel_sdvo_detect(struct drm_connector *connect
|
||||
struct intel_output *intel_output = to_intel_output(connector);
|
||||
struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
|
||||
|
||||
intel_sdvo_write_cmd(intel_output, SDVO_CMD_GET_ATTACHED_DISPLAYS, NULL, 0);
|
||||
intel_sdvo_write_cmd(intel_output,
|
||||
SDVO_CMD_GET_ATTACHED_DISPLAYS, NULL, 0);
|
||||
status = intel_sdvo_read_response(intel_output, &response, 2);
|
||||
|
||||
DRM_DEBUG_KMS("SDVO response %d %d\n", response & 0xff, response >> 8);
|
||||
@@ -1539,50 +1601,32 @@ static enum drm_connector_status intel_sdvo_detect(struct drm_connector *connect
|
||||
static void intel_sdvo_get_ddc_modes(struct drm_connector *connector)
|
||||
{
|
||||
struct intel_output *intel_output = to_intel_output(connector);
|
||||
struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
|
||||
int num_modes;
|
||||
|
||||
/* set the bus switch and get the modes */
|
||||
intel_ddc_get_modes(intel_output);
|
||||
num_modes = intel_ddc_get_modes(intel_output);
|
||||
|
||||
#if 0
|
||||
struct drm_device *dev = encoder->dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
/* Mac mini hack. On this device, I get DDC through the analog, which
|
||||
* load-detects as disconnected. I fail to DDC through the SDVO DDC,
|
||||
* but it does load-detect as connected. So, just steal the DDC bits
|
||||
* from analog when we fail at finding it the right way.
|
||||
/*
|
||||
* Mac mini hack. On this device, the DVI-I connector shares one DDC
|
||||
* link between analog and digital outputs. So, if the regular SDVO
|
||||
* DDC fails, check to see if the analog output is disconnected, in
|
||||
* which case we'll look there for the digital DDC data.
|
||||
*/
|
||||
crt = xf86_config->output[0];
|
||||
intel_output = crt->driver_private;
|
||||
if (intel_output->type == I830_OUTPUT_ANALOG &&
|
||||
crt->funcs->detect(crt) == XF86OutputStatusDisconnected) {
|
||||
I830I2CInit(pScrn, &intel_output->pDDCBus, GPIOA, "CRTDDC_A");
|
||||
edid_mon = xf86OutputGetEDID(crt, intel_output->pDDCBus);
|
||||
xf86DestroyI2CBusRec(intel_output->pDDCBus, true, true);
|
||||
if (num_modes == 0 &&
|
||||
sdvo_priv->analog_ddc_bus &&
|
||||
!intel_analog_is_connected(intel_output->base.dev)) {
|
||||
struct i2c_adapter *digital_ddc_bus;
|
||||
|
||||
/* Switch to the analog ddc bus and try that
|
||||
*/
|
||||
digital_ddc_bus = intel_output->ddc_bus;
|
||||
intel_output->ddc_bus = sdvo_priv->analog_ddc_bus;
|
||||
|
||||
(void) intel_ddc_get_modes(intel_output);
|
||||
|
||||
intel_output->ddc_bus = digital_ddc_bus;
|
||||
}
|
||||
if (edid_mon) {
|
||||
xf86OutputSetEDID(output, edid_mon);
|
||||
modes = xf86OutputGetEDIDModes(output);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* This function checks the current TV format, and chooses a default if
|
||||
* it hasn't been set.
|
||||
*/
|
||||
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;
|
||||
uint8_t status;
|
||||
|
||||
intel_sdvo_write_cmd(output, SDVO_CMD_GET_TV_FORMAT, NULL, 0);
|
||||
status = intel_sdvo_read_response(output, &format, sizeof(format));
|
||||
if (status != SDVO_CMD_STATUS_SUCCESS)
|
||||
return;
|
||||
|
||||
memcpy(&dev_priv->tv_format, &format, sizeof(format));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1655,17 +1699,26 @@ 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;
|
||||
uint32_t reply = 0, format_map = 0;
|
||||
int i;
|
||||
uint8_t status;
|
||||
int i = 0;
|
||||
|
||||
intel_sdvo_check_tv_format(output);
|
||||
|
||||
/* 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));
|
||||
for (i = 0; i < TV_FORMAT_NUM; i++)
|
||||
if (tv_format_names[i] == sdvo_priv->tv_format_name)
|
||||
break;
|
||||
|
||||
format_map = (1 << i);
|
||||
memcpy(&tv_res, &format_map,
|
||||
sizeof(struct intel_sdvo_sdtv_resolution_request) >
|
||||
sizeof(format_map) ? sizeof(format_map) :
|
||||
sizeof(struct intel_sdvo_sdtv_resolution_request));
|
||||
|
||||
intel_sdvo_set_target_output(output, sdvo_priv->controlled_output);
|
||||
|
||||
intel_sdvo_write_cmd(output, SDVO_CMD_GET_SDTV_RESOLUTION_SUPPORT,
|
||||
&tv_res, sizeof(tv_res));
|
||||
status = intel_sdvo_read_response(output, &reply, 3);
|
||||
@@ -1680,6 +1733,7 @@ static void intel_sdvo_get_tv_modes(struct drm_connector *connector)
|
||||
if (nmode)
|
||||
drm_mode_probed_add(connector, nmode);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void intel_sdvo_get_lvds_modes(struct drm_connector *connector)
|
||||
@@ -1747,17 +1801,62 @@ static void intel_sdvo_destroy(struct drm_connector *connector)
|
||||
intel_i2c_destroy(intel_output->i2c_bus);
|
||||
if (intel_output->ddc_bus)
|
||||
intel_i2c_destroy(intel_output->ddc_bus);
|
||||
if (sdvo_priv->analog_ddc_bus)
|
||||
intel_i2c_destroy(sdvo_priv->analog_ddc_bus);
|
||||
|
||||
if (sdvo_priv->sdvo_lvds_fixed_mode != NULL)
|
||||
drm_mode_destroy(connector->dev,
|
||||
sdvo_priv->sdvo_lvds_fixed_mode);
|
||||
|
||||
if (sdvo_priv->tv_format_property)
|
||||
drm_property_destroy(connector->dev,
|
||||
sdvo_priv->tv_format_property);
|
||||
|
||||
drm_sysfs_connector_remove(connector);
|
||||
drm_connector_cleanup(connector);
|
||||
|
||||
kfree(intel_output);
|
||||
}
|
||||
|
||||
static int
|
||||
intel_sdvo_set_property(struct drm_connector *connector,
|
||||
struct drm_property *property,
|
||||
uint64_t val)
|
||||
{
|
||||
struct intel_output *intel_output = to_intel_output(connector);
|
||||
struct intel_sdvo_priv *sdvo_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 == sdvo_priv->tv_format_property) {
|
||||
if (val >= TV_FORMAT_NUM) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
if (sdvo_priv->tv_format_name ==
|
||||
sdvo_priv->tv_format_supported[val])
|
||||
goto out;
|
||||
|
||||
sdvo_priv->tv_format_name = sdvo_priv->tv_format_supported[val];
|
||||
changed = true;
|
||||
} else {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (changed && crtc)
|
||||
drm_crtc_helper_set_mode(crtc, &crtc->mode, crtc->x,
|
||||
crtc->y, crtc->fb);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct drm_encoder_helper_funcs intel_sdvo_helper_funcs = {
|
||||
.dpms = intel_sdvo_dpms,
|
||||
.mode_fixup = intel_sdvo_mode_fixup,
|
||||
@@ -1772,6 +1871,7 @@ static const struct drm_connector_funcs intel_sdvo_connector_funcs = {
|
||||
.restore = intel_sdvo_restore,
|
||||
.detect = intel_sdvo_detect,
|
||||
.fill_modes = drm_helper_probe_single_connector_modes,
|
||||
.set_property = intel_sdvo_set_property,
|
||||
.destroy = intel_sdvo_destroy,
|
||||
};
|
||||
|
||||
@@ -1966,6 +2066,9 @@ intel_sdvo_output_setup(struct intel_output *intel_output, uint16_t flags)
|
||||
intel_sdvo_set_colorimetry(intel_output,
|
||||
SDVO_COLORIMETRY_RGB256);
|
||||
connector->connector_type = DRM_MODE_CONNECTOR_HDMIA;
|
||||
intel_output->clone_mask =
|
||||
(1 << INTEL_SDVO_NON_TV_CLONE_BIT) |
|
||||
(1 << INTEL_ANALOG_CLONE_BIT);
|
||||
}
|
||||
} else if (flags & SDVO_OUTPUT_SVID0) {
|
||||
|
||||
@@ -1974,11 +2077,14 @@ intel_sdvo_output_setup(struct intel_output *intel_output, uint16_t flags)
|
||||
connector->connector_type = DRM_MODE_CONNECTOR_SVIDEO;
|
||||
sdvo_priv->is_tv = true;
|
||||
intel_output->needs_tv_clock = true;
|
||||
intel_output->clone_mask = 1 << INTEL_SDVO_TV_CLONE_BIT;
|
||||
} else if (flags & SDVO_OUTPUT_RGB0) {
|
||||
|
||||
sdvo_priv->controlled_output = SDVO_OUTPUT_RGB0;
|
||||
encoder->encoder_type = DRM_MODE_ENCODER_DAC;
|
||||
connector->connector_type = DRM_MODE_CONNECTOR_VGA;
|
||||
intel_output->clone_mask = (1 << INTEL_SDVO_NON_TV_CLONE_BIT) |
|
||||
(1 << INTEL_ANALOG_CLONE_BIT);
|
||||
} else if (flags & SDVO_OUTPUT_RGB1) {
|
||||
|
||||
sdvo_priv->controlled_output = SDVO_OUTPUT_RGB1;
|
||||
@@ -1990,12 +2096,16 @@ intel_sdvo_output_setup(struct intel_output *intel_output, uint16_t flags)
|
||||
encoder->encoder_type = DRM_MODE_ENCODER_LVDS;
|
||||
connector->connector_type = DRM_MODE_CONNECTOR_LVDS;
|
||||
sdvo_priv->is_lvds = true;
|
||||
intel_output->clone_mask = (1 << INTEL_ANALOG_CLONE_BIT) |
|
||||
(1 << INTEL_SDVO_LVDS_CLONE_BIT);
|
||||
} else if (flags & SDVO_OUTPUT_LVDS1) {
|
||||
|
||||
sdvo_priv->controlled_output = SDVO_OUTPUT_LVDS1;
|
||||
encoder->encoder_type = DRM_MODE_ENCODER_LVDS;
|
||||
connector->connector_type = DRM_MODE_CONNECTOR_LVDS;
|
||||
sdvo_priv->is_lvds = true;
|
||||
intel_output->clone_mask = (1 << INTEL_ANALOG_CLONE_BIT) |
|
||||
(1 << INTEL_SDVO_LVDS_CLONE_BIT);
|
||||
} else {
|
||||
|
||||
unsigned char bytes[2];
|
||||
@@ -2007,6 +2117,7 @@ intel_sdvo_output_setup(struct intel_output *intel_output, uint16_t flags)
|
||||
bytes[0], bytes[1]);
|
||||
ret = false;
|
||||
}
|
||||
intel_output->crtc_mask = (1 << 0) | (1 << 1);
|
||||
|
||||
if (ret && registered)
|
||||
ret = drm_sysfs_connector_add(connector) == 0 ? true : false;
|
||||
@@ -2016,6 +2127,55 @@ intel_sdvo_output_setup(struct intel_output *intel_output, uint16_t flags)
|
||||
|
||||
}
|
||||
|
||||
static void intel_sdvo_tv_create_property(struct drm_connector *connector)
|
||||
{
|
||||
struct intel_output *intel_output = to_intel_output(connector);
|
||||
struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
|
||||
struct intel_sdvo_tv_format format;
|
||||
uint32_t format_map, i;
|
||||
uint8_t status;
|
||||
|
||||
intel_sdvo_set_target_output(intel_output,
|
||||
sdvo_priv->controlled_output);
|
||||
|
||||
intel_sdvo_write_cmd(intel_output,
|
||||
SDVO_CMD_GET_SUPPORTED_TV_FORMATS, NULL, 0);
|
||||
status = intel_sdvo_read_response(intel_output,
|
||||
&format, sizeof(format));
|
||||
if (status != SDVO_CMD_STATUS_SUCCESS)
|
||||
return;
|
||||
|
||||
memcpy(&format_map, &format, sizeof(format) > sizeof(format_map) ?
|
||||
sizeof(format_map) : sizeof(format));
|
||||
|
||||
if (format_map == 0)
|
||||
return;
|
||||
|
||||
sdvo_priv->format_supported_num = 0;
|
||||
for (i = 0 ; i < TV_FORMAT_NUM; i++)
|
||||
if (format_map & (1 << i)) {
|
||||
sdvo_priv->tv_format_supported
|
||||
[sdvo_priv->format_supported_num++] =
|
||||
tv_format_names[i];
|
||||
}
|
||||
|
||||
|
||||
sdvo_priv->tv_format_property =
|
||||
drm_property_create(
|
||||
connector->dev, DRM_MODE_PROP_ENUM,
|
||||
"mode", sdvo_priv->format_supported_num);
|
||||
|
||||
for (i = 0; i < sdvo_priv->format_supported_num; i++)
|
||||
drm_property_add_enum(
|
||||
sdvo_priv->tv_format_property, i,
|
||||
i, sdvo_priv->tv_format_supported[i]);
|
||||
|
||||
sdvo_priv->tv_format_name = sdvo_priv->tv_format_supported[0];
|
||||
drm_connector_attach_property(
|
||||
connector, sdvo_priv->tv_format_property, 0);
|
||||
|
||||
}
|
||||
|
||||
bool intel_sdvo_init(struct drm_device *dev, int output_device)
|
||||
{
|
||||
struct drm_connector *connector;
|
||||
@@ -2060,10 +2220,15 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device)
|
||||
}
|
||||
|
||||
/* setup the DDC bus. */
|
||||
if (output_device == SDVOB)
|
||||
if (output_device == SDVOB) {
|
||||
intel_output->ddc_bus = intel_i2c_create(dev, GPIOE, "SDVOB DDC BUS");
|
||||
else
|
||||
sdvo_priv->analog_ddc_bus = intel_i2c_create(dev, GPIOA,
|
||||
"SDVOB/VGA DDC BUS");
|
||||
} else {
|
||||
intel_output->ddc_bus = intel_i2c_create(dev, GPIOE, "SDVOC DDC BUS");
|
||||
sdvo_priv->analog_ddc_bus = intel_i2c_create(dev, GPIOA,
|
||||
"SDVOC/VGA DDC BUS");
|
||||
}
|
||||
|
||||
if (intel_output->ddc_bus == NULL)
|
||||
goto err_i2c;
|
||||
@@ -2097,6 +2262,8 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device)
|
||||
drm_encoder_helper_add(&intel_output->enc, &intel_sdvo_helper_funcs);
|
||||
|
||||
drm_mode_connector_attach_encoder(&intel_output->base, &intel_output->enc);
|
||||
if (sdvo_priv->is_tv)
|
||||
intel_sdvo_tv_create_property(connector);
|
||||
drm_sysfs_connector_add(connector);
|
||||
|
||||
intel_sdvo_select_ddc_bus(sdvo_priv);
|
||||
@@ -2129,6 +2296,8 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device)
|
||||
return true;
|
||||
|
||||
err_i2c:
|
||||
if (sdvo_priv->analog_ddc_bus != NULL)
|
||||
intel_i2c_destroy(sdvo_priv->analog_ddc_bus);
|
||||
if (intel_output->ddc_bus != NULL)
|
||||
intel_i2c_destroy(intel_output->ddc_bus);
|
||||
if (intel_output->i2c_bus != NULL)
|
||||
|
@@ -1437,6 +1437,35 @@ intel_tv_detect_type (struct drm_crtc *crtc, struct intel_output *intel_output)
|
||||
return type;
|
||||
}
|
||||
|
||||
/*
|
||||
* Here we set accurate tv format according to connector type
|
||||
* i.e Component TV should not be assigned by NTSC or PAL
|
||||
*/
|
||||
static void intel_tv_find_better_format(struct drm_connector *connector)
|
||||
{
|
||||
struct intel_output *intel_output = to_intel_output(connector);
|
||||
struct intel_tv_priv *tv_priv = intel_output->dev_priv;
|
||||
const struct tv_mode *tv_mode = intel_tv_mode_find(intel_output);
|
||||
int i;
|
||||
|
||||
if ((tv_priv->type == DRM_MODE_CONNECTOR_Component) ==
|
||||
tv_mode->component_only)
|
||||
return;
|
||||
|
||||
|
||||
for (i = 0; i < sizeof(tv_modes) / sizeof(*tv_modes); i++) {
|
||||
tv_mode = tv_modes + i;
|
||||
|
||||
if ((tv_priv->type == DRM_MODE_CONNECTOR_Component) ==
|
||||
tv_mode->component_only)
|
||||
break;
|
||||
}
|
||||
|
||||
tv_priv->tv_format = tv_mode->name;
|
||||
drm_connector_property_set_value(connector,
|
||||
connector->dev->mode_config.tv_mode_property, i);
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect the TV connection.
|
||||
*
|
||||
@@ -1473,6 +1502,7 @@ intel_tv_detect(struct drm_connector *connector)
|
||||
if (type < 0)
|
||||
return connector_status_disconnected;
|
||||
|
||||
intel_tv_find_better_format(connector);
|
||||
return connector_status_connected;
|
||||
}
|
||||
|
||||
@@ -1718,6 +1748,7 @@ intel_tv_init(struct drm_device *dev)
|
||||
if (!intel_output) {
|
||||
return;
|
||||
}
|
||||
|
||||
connector = &intel_output->base;
|
||||
|
||||
drm_connector_init(dev, connector, &intel_tv_connector_funcs,
|
||||
@@ -1729,6 +1760,7 @@ intel_tv_init(struct drm_device *dev)
|
||||
drm_mode_connector_attach_encoder(&intel_output->base, &intel_output->enc);
|
||||
tv_priv = (struct intel_tv_priv *)(intel_output + 1);
|
||||
intel_output->type = INTEL_OUTPUT_TVOUT;
|
||||
intel_output->clone_mask = (1 << INTEL_TV_CLONE_BIT);
|
||||
intel_output->enc.possible_crtcs = ((1 << 0) | (1 << 1));
|
||||
intel_output->enc.possible_clones = (1 << INTEL_OUTPUT_TVOUT);
|
||||
intel_output->dev_priv = tv_priv;
|
||||
|
Referência em uma nova issue
Block a user