Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/anholt/drm-intel
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/anholt/drm-intel: (22 commits) drm/i915: Fix read outside array bounds in restoring the SWF10 range. drm/i915: Use our own workqueue to avoid wedging the system along with the GPU. drm/i915: Add support for dual-channel LVDS on 8xx. drm/i915: Return disconnected for SDVO DVI when there's no digital EDID. drm/i915: Choose real sdvo output according to result from detection drm/i915: Set preferred mode for integrated TV according to TV format drm/i915: fix 845G FIFO size & burst length drm/i915: fix VGA detect on IGDNG drm/i915: Add eDP support on IGDNG mobile chip drm/i915: enable DisplayPort support on IGDNG drm/i915: Fix channel ending action for DP aux transaction drm/i915: fix issue in display pipe setup on IGDNG drm/i915: disable VGA plane reliably drm/I915: Fix offset to DVO timings in LVDS data drm/i915: hdmi detection according by reading edid drm/i915: correct self-refresh calculation in "everything off" case drm/i915: handle FIFO oversubsription correctly drm/i915: FIFO watermark calculation fixes drm/i915: ignore lvds on AOpen Mini PC MP-915 drm/i915: Allow frame buffers up to 4096x4096 on 915/945 class hardware ...
This commit is contained in:
Коммит
b32b8e645e
|
@ -1186,6 +1186,13 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
|
|||
if (ret)
|
||||
goto out_iomapfree;
|
||||
|
||||
dev_priv->wq = create_workqueue("i915");
|
||||
if (dev_priv->wq == NULL) {
|
||||
DRM_ERROR("Failed to create our workqueue.\n");
|
||||
ret = -ENOMEM;
|
||||
goto out_iomapfree;
|
||||
}
|
||||
|
||||
/* enable GEM by default */
|
||||
dev_priv->has_gem = 1;
|
||||
|
||||
|
@ -1211,7 +1218,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
|
|||
if (!I915_NEED_GFX_HWS(dev)) {
|
||||
ret = i915_init_phys_hws(dev);
|
||||
if (ret != 0)
|
||||
goto out_iomapfree;
|
||||
goto out_workqueue_free;
|
||||
}
|
||||
|
||||
i915_get_mem_freq(dev);
|
||||
|
@ -1245,7 +1252,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
|
|||
ret = i915_load_modeset_init(dev, prealloc_size, agp_size);
|
||||
if (ret < 0) {
|
||||
DRM_ERROR("failed to init modeset\n");
|
||||
goto out_rmmap;
|
||||
goto out_workqueue_free;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1256,6 +1263,8 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
|
|||
|
||||
return 0;
|
||||
|
||||
out_workqueue_free:
|
||||
destroy_workqueue(dev_priv->wq);
|
||||
out_iomapfree:
|
||||
io_mapping_free(dev_priv->mm.gtt_mapping);
|
||||
out_rmmap:
|
||||
|
@ -1269,6 +1278,8 @@ int i915_driver_unload(struct drm_device *dev)
|
|||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
|
||||
destroy_workqueue(dev_priv->wq);
|
||||
|
||||
io_mapping_free(dev_priv->mm.gtt_mapping);
|
||||
if (dev_priv->mm.gtt_mtrr >= 0) {
|
||||
mtrr_del(dev_priv->mm.gtt_mtrr, dev->agp->base,
|
||||
|
|
|
@ -219,6 +219,7 @@ typedef struct drm_i915_private {
|
|||
unsigned int lvds_vbt:1;
|
||||
unsigned int int_crt_support:1;
|
||||
unsigned int lvds_use_ssc:1;
|
||||
unsigned int edp_support:1;
|
||||
int lvds_ssc_freq;
|
||||
|
||||
struct drm_i915_fence_reg fence_regs[16]; /* assume 965 */
|
||||
|
@ -229,6 +230,8 @@ typedef struct drm_i915_private {
|
|||
|
||||
spinlock_t error_lock;
|
||||
struct drm_i915_error_state *first_error;
|
||||
struct work_struct error_work;
|
||||
struct workqueue_struct *wq;
|
||||
|
||||
/* Register state */
|
||||
u8 saveLBB;
|
||||
|
@ -888,6 +891,7 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller);
|
|||
IS_I915GM(dev)))
|
||||
#define SUPPORTS_INTEGRATED_HDMI(dev) (IS_G4X(dev) || IS_IGDNG(dev))
|
||||
#define SUPPORTS_INTEGRATED_DP(dev) (IS_G4X(dev) || IS_IGDNG(dev))
|
||||
#define SUPPORTS_EDP(dev) (IS_IGDNG_M(dev))
|
||||
#define I915_HAS_HOTPLUG(dev) (IS_I945G(dev) || IS_I945GM(dev) || IS_I965G(dev))
|
||||
/* dsparb controlled by hw only */
|
||||
#define DSPARB_HWCONTROL(dev) (IS_G4X(dev) || IS_IGDNG(dev))
|
||||
|
|
|
@ -1570,7 +1570,7 @@ i915_add_request(struct drm_device *dev, struct drm_file *file_priv,
|
|||
}
|
||||
|
||||
if (was_empty && !dev_priv->mm.suspended)
|
||||
schedule_delayed_work(&dev_priv->mm.retire_work, HZ);
|
||||
queue_delayed_work(dev_priv->wq, &dev_priv->mm.retire_work, HZ);
|
||||
return seqno;
|
||||
}
|
||||
|
||||
|
@ -1719,7 +1719,7 @@ i915_gem_retire_work_handler(struct work_struct *work)
|
|||
i915_gem_retire_requests(dev);
|
||||
if (!dev_priv->mm.suspended &&
|
||||
!list_empty(&dev_priv->mm.request_list))
|
||||
schedule_delayed_work(&dev_priv->mm.retire_work, HZ);
|
||||
queue_delayed_work(dev_priv->wq, &dev_priv->mm.retire_work, HZ);
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
}
|
||||
|
||||
|
|
|
@ -343,6 +343,8 @@ static int i915_error_state(struct seq_file *m, void *unused)
|
|||
|
||||
error = dev_priv->first_error;
|
||||
|
||||
seq_printf(m, "Time: %ld s %ld us\n", error->time.tv_sec,
|
||||
error->time.tv_usec);
|
||||
seq_printf(m, "EIR: 0x%08x\n", error->eir);
|
||||
seq_printf(m, " PGTBL_ER: 0x%08x\n", error->pgtbl_er);
|
||||
seq_printf(m, " INSTPM: 0x%08x\n", error->instpm);
|
||||
|
|
|
@ -290,6 +290,35 @@ irqreturn_t igdng_irq_handler(struct drm_device *dev)
|
|||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* i915_error_work_func - do process context error handling work
|
||||
* @work: work struct
|
||||
*
|
||||
* Fire an error uevent so userspace can see that a hang or error
|
||||
* was detected.
|
||||
*/
|
||||
static void i915_error_work_func(struct work_struct *work)
|
||||
{
|
||||
drm_i915_private_t *dev_priv = container_of(work, drm_i915_private_t,
|
||||
error_work);
|
||||
struct drm_device *dev = dev_priv->dev;
|
||||
char *event_string = "ERROR=1";
|
||||
char *envp[] = { event_string, NULL };
|
||||
|
||||
DRM_DEBUG("generating error event\n");
|
||||
|
||||
kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, envp);
|
||||
}
|
||||
|
||||
/**
|
||||
* i915_capture_error_state - capture an error record for later analysis
|
||||
* @dev: drm device
|
||||
*
|
||||
* Should be called when an error is detected (either a hang or an error
|
||||
* interrupt) to capture error state from the time of the error. Fills
|
||||
* out a structure which becomes available in debugfs for user level tools
|
||||
* to pick up.
|
||||
*/
|
||||
static void i915_capture_error_state(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
|
@ -325,97 +354,66 @@ static void i915_capture_error_state(struct drm_device *dev)
|
|||
error->acthd = I915_READ(ACTHD_I965);
|
||||
}
|
||||
|
||||
do_gettimeofday(&error->time);
|
||||
|
||||
dev_priv->first_error = error;
|
||||
|
||||
out:
|
||||
spin_unlock_irqrestore(&dev_priv->error_lock, flags);
|
||||
}
|
||||
|
||||
irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
|
||||
/**
|
||||
* i915_handle_error - handle an error interrupt
|
||||
* @dev: drm device
|
||||
*
|
||||
* Do some basic checking of regsiter state at error interrupt time and
|
||||
* dump it to the syslog. Also call i915_capture_error_state() to make
|
||||
* sure we get a record and make it available in debugfs. Fire a uevent
|
||||
* so userspace knows something bad happened (should trigger collection
|
||||
* of a ring dump etc.).
|
||||
*/
|
||||
static void i915_handle_error(struct drm_device *dev)
|
||||
{
|
||||
struct drm_device *dev = (struct drm_device *) arg;
|
||||
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
|
||||
struct drm_i915_master_private *master_priv;
|
||||
u32 iir, new_iir;
|
||||
u32 pipea_stats, pipeb_stats;
|
||||
u32 vblank_status;
|
||||
u32 vblank_enable;
|
||||
int vblank = 0;
|
||||
unsigned long irqflags;
|
||||
int irq_received;
|
||||
int ret = IRQ_NONE;
|
||||
|
||||
atomic_inc(&dev_priv->irq_received);
|
||||
|
||||
if (IS_IGDNG(dev))
|
||||
return igdng_irq_handler(dev);
|
||||
|
||||
iir = I915_READ(IIR);
|
||||
|
||||
if (IS_I965G(dev)) {
|
||||
vblank_status = I915_START_VBLANK_INTERRUPT_STATUS;
|
||||
vblank_enable = PIPE_START_VBLANK_INTERRUPT_ENABLE;
|
||||
} else {
|
||||
vblank_status = I915_VBLANK_INTERRUPT_STATUS;
|
||||
vblank_enable = I915_VBLANK_INTERRUPT_ENABLE;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
irq_received = iir != 0;
|
||||
|
||||
/* Can't rely on pipestat interrupt bit in iir as it might
|
||||
* have been cleared after the pipestat interrupt was received.
|
||||
* It doesn't set the bit in iir again, but it still produces
|
||||
* interrupts (for non-MSI).
|
||||
*/
|
||||
spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags);
|
||||
pipea_stats = I915_READ(PIPEASTAT);
|
||||
pipeb_stats = I915_READ(PIPEBSTAT);
|
||||
|
||||
/*
|
||||
* Clear the PIPE(A|B)STAT regs before the IIR
|
||||
*/
|
||||
if (pipea_stats & 0x8000ffff) {
|
||||
if (pipea_stats & PIPE_FIFO_UNDERRUN_STATUS)
|
||||
DRM_DEBUG("pipe a underrun\n");
|
||||
I915_WRITE(PIPEASTAT, pipea_stats);
|
||||
irq_received = 1;
|
||||
}
|
||||
|
||||
if (pipeb_stats & 0x8000ffff) {
|
||||
if (pipeb_stats & PIPE_FIFO_UNDERRUN_STATUS)
|
||||
DRM_DEBUG("pipe b underrun\n");
|
||||
I915_WRITE(PIPEBSTAT, pipeb_stats);
|
||||
irq_received = 1;
|
||||
}
|
||||
spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags);
|
||||
|
||||
if (!irq_received)
|
||||
break;
|
||||
|
||||
ret = IRQ_HANDLED;
|
||||
|
||||
/* Consume port. Then clear IIR or we'll miss events */
|
||||
if ((I915_HAS_HOTPLUG(dev)) &&
|
||||
(iir & I915_DISPLAY_PORT_INTERRUPT)) {
|
||||
u32 hotplug_status = I915_READ(PORT_HOTPLUG_STAT);
|
||||
|
||||
DRM_DEBUG("hotplug event received, stat 0x%08x\n",
|
||||
hotplug_status);
|
||||
if (hotplug_status & dev_priv->hotplug_supported_mask)
|
||||
schedule_work(&dev_priv->hotplug_work);
|
||||
|
||||
I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status);
|
||||
I915_READ(PORT_HOTPLUG_STAT);
|
||||
}
|
||||
|
||||
if (iir & I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT) {
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
u32 eir = I915_READ(EIR);
|
||||
u32 pipea_stats = I915_READ(PIPEASTAT);
|
||||
u32 pipeb_stats = I915_READ(PIPEBSTAT);
|
||||
|
||||
i915_capture_error_state(dev);
|
||||
|
||||
printk(KERN_ERR "render error detected, EIR: 0x%08x\n",
|
||||
eir);
|
||||
|
||||
if (IS_G4X(dev)) {
|
||||
if (eir & (GM45_ERROR_MEM_PRIV | GM45_ERROR_CP_PRIV)) {
|
||||
u32 ipeir = I915_READ(IPEIR_I965);
|
||||
|
||||
printk(KERN_ERR " IPEIR: 0x%08x\n",
|
||||
I915_READ(IPEIR_I965));
|
||||
printk(KERN_ERR " IPEHR: 0x%08x\n",
|
||||
I915_READ(IPEHR_I965));
|
||||
printk(KERN_ERR " INSTDONE: 0x%08x\n",
|
||||
I915_READ(INSTDONE_I965));
|
||||
printk(KERN_ERR " INSTPS: 0x%08x\n",
|
||||
I915_READ(INSTPS));
|
||||
printk(KERN_ERR " INSTDONE1: 0x%08x\n",
|
||||
I915_READ(INSTDONE1));
|
||||
printk(KERN_ERR " ACTHD: 0x%08x\n",
|
||||
I915_READ(ACTHD_I965));
|
||||
I915_WRITE(IPEIR_I965, ipeir);
|
||||
(void)I915_READ(IPEIR_I965);
|
||||
}
|
||||
if (eir & GM45_ERROR_PAGE_TABLE) {
|
||||
u32 pgtbl_err = I915_READ(PGTBL_ER);
|
||||
printk(KERN_ERR "page table error\n");
|
||||
printk(KERN_ERR " PGTBL_ER: 0x%08x\n",
|
||||
pgtbl_err);
|
||||
I915_WRITE(PGTBL_ER, pgtbl_err);
|
||||
(void)I915_READ(PGTBL_ER);
|
||||
}
|
||||
}
|
||||
|
||||
if (IS_I9XX(dev)) {
|
||||
if (eir & I915_ERROR_PAGE_TABLE) {
|
||||
u32 pgtbl_err = I915_READ(PGTBL_ER);
|
||||
printk(KERN_ERR "page table error\n");
|
||||
|
@ -424,6 +422,8 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
|
|||
I915_WRITE(PGTBL_ER, pgtbl_err);
|
||||
(void)I915_READ(PGTBL_ER);
|
||||
}
|
||||
}
|
||||
|
||||
if (eir & I915_ERROR_MEMORY_REFRESH) {
|
||||
printk(KERN_ERR "memory refresh error\n");
|
||||
printk(KERN_ERR "PIPEASTAT: 0x%08x\n",
|
||||
|
@ -481,6 +481,90 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
|
|||
I915_WRITE(EMR, I915_READ(EMR) | eir);
|
||||
I915_WRITE(IIR, I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT);
|
||||
}
|
||||
|
||||
queue_work(dev_priv->wq, &dev_priv->error_work);
|
||||
}
|
||||
|
||||
irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
|
||||
{
|
||||
struct drm_device *dev = (struct drm_device *) arg;
|
||||
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
|
||||
struct drm_i915_master_private *master_priv;
|
||||
u32 iir, new_iir;
|
||||
u32 pipea_stats, pipeb_stats;
|
||||
u32 vblank_status;
|
||||
u32 vblank_enable;
|
||||
int vblank = 0;
|
||||
unsigned long irqflags;
|
||||
int irq_received;
|
||||
int ret = IRQ_NONE;
|
||||
|
||||
atomic_inc(&dev_priv->irq_received);
|
||||
|
||||
if (IS_IGDNG(dev))
|
||||
return igdng_irq_handler(dev);
|
||||
|
||||
iir = I915_READ(IIR);
|
||||
|
||||
if (IS_I965G(dev)) {
|
||||
vblank_status = I915_START_VBLANK_INTERRUPT_STATUS;
|
||||
vblank_enable = PIPE_START_VBLANK_INTERRUPT_ENABLE;
|
||||
} else {
|
||||
vblank_status = I915_VBLANK_INTERRUPT_STATUS;
|
||||
vblank_enable = I915_VBLANK_INTERRUPT_ENABLE;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
irq_received = iir != 0;
|
||||
|
||||
/* Can't rely on pipestat interrupt bit in iir as it might
|
||||
* have been cleared after the pipestat interrupt was received.
|
||||
* It doesn't set the bit in iir again, but it still produces
|
||||
* interrupts (for non-MSI).
|
||||
*/
|
||||
spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags);
|
||||
pipea_stats = I915_READ(PIPEASTAT);
|
||||
pipeb_stats = I915_READ(PIPEBSTAT);
|
||||
|
||||
if (iir & I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT)
|
||||
i915_handle_error(dev);
|
||||
|
||||
/*
|
||||
* Clear the PIPE(A|B)STAT regs before the IIR
|
||||
*/
|
||||
if (pipea_stats & 0x8000ffff) {
|
||||
if (pipea_stats & PIPE_FIFO_UNDERRUN_STATUS)
|
||||
DRM_DEBUG("pipe a underrun\n");
|
||||
I915_WRITE(PIPEASTAT, pipea_stats);
|
||||
irq_received = 1;
|
||||
}
|
||||
|
||||
if (pipeb_stats & 0x8000ffff) {
|
||||
if (pipeb_stats & PIPE_FIFO_UNDERRUN_STATUS)
|
||||
DRM_DEBUG("pipe b underrun\n");
|
||||
I915_WRITE(PIPEBSTAT, pipeb_stats);
|
||||
irq_received = 1;
|
||||
}
|
||||
spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags);
|
||||
|
||||
if (!irq_received)
|
||||
break;
|
||||
|
||||
ret = IRQ_HANDLED;
|
||||
|
||||
/* Consume port. Then clear IIR or we'll miss events */
|
||||
if ((I915_HAS_HOTPLUG(dev)) &&
|
||||
(iir & I915_DISPLAY_PORT_INTERRUPT)) {
|
||||
u32 hotplug_status = I915_READ(PORT_HOTPLUG_STAT);
|
||||
|
||||
DRM_DEBUG("hotplug event received, stat 0x%08x\n",
|
||||
hotplug_status);
|
||||
if (hotplug_status & dev_priv->hotplug_supported_mask)
|
||||
queue_work(dev_priv->wq,
|
||||
&dev_priv->hotplug_work);
|
||||
|
||||
I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status);
|
||||
I915_READ(PORT_HOTPLUG_STAT);
|
||||
}
|
||||
|
||||
I915_WRITE(IIR, iir);
|
||||
|
@ -830,6 +914,7 @@ void i915_driver_irq_preinstall(struct drm_device * dev)
|
|||
atomic_set(&dev_priv->irq_received, 0);
|
||||
|
||||
INIT_WORK(&dev_priv->hotplug_work, i915_hotplug_work_func);
|
||||
INIT_WORK(&dev_priv->error_work, i915_error_work_func);
|
||||
|
||||
if (IS_IGDNG(dev)) {
|
||||
igdng_irq_preinstall(dev);
|
||||
|
|
|
@ -1395,6 +1395,7 @@
|
|||
#define TV_V_CHROMA_42 0x684a8
|
||||
|
||||
/* Display Port */
|
||||
#define DP_A 0x64000 /* eDP */
|
||||
#define DP_B 0x64100
|
||||
#define DP_C 0x64200
|
||||
#define DP_D 0x64300
|
||||
|
@ -1437,13 +1438,22 @@
|
|||
/* Mystic DPCD version 1.1 special mode */
|
||||
#define DP_ENHANCED_FRAMING (1 << 18)
|
||||
|
||||
/* eDP */
|
||||
#define DP_PLL_FREQ_270MHZ (0 << 16)
|
||||
#define DP_PLL_FREQ_160MHZ (1 << 16)
|
||||
#define DP_PLL_FREQ_MASK (3 << 16)
|
||||
|
||||
/** locked once port is enabled */
|
||||
#define DP_PORT_REVERSAL (1 << 15)
|
||||
|
||||
/* eDP */
|
||||
#define DP_PLL_ENABLE (1 << 14)
|
||||
|
||||
/** sends the clock on lane 15 of the PEG for debug */
|
||||
#define DP_CLOCK_OUTPUT_ENABLE (1 << 13)
|
||||
|
||||
#define DP_SCRAMBLING_DISABLE (1 << 12)
|
||||
#define DP_SCRAMBLING_DISABLE_IGDNG (1 << 7)
|
||||
|
||||
/** limit RGB values to avoid confusing TVs */
|
||||
#define DP_COLOR_RANGE_16_235 (1 << 8)
|
||||
|
@ -1463,6 +1473,13 @@
|
|||
* is 20 bytes in each direction, hence the 5 fixed
|
||||
* data registers
|
||||
*/
|
||||
#define DPA_AUX_CH_CTL 0x64010
|
||||
#define DPA_AUX_CH_DATA1 0x64014
|
||||
#define DPA_AUX_CH_DATA2 0x64018
|
||||
#define DPA_AUX_CH_DATA3 0x6401c
|
||||
#define DPA_AUX_CH_DATA4 0x64020
|
||||
#define DPA_AUX_CH_DATA5 0x64024
|
||||
|
||||
#define DPB_AUX_CH_CTL 0x64110
|
||||
#define DPB_AUX_CH_DATA1 0x64114
|
||||
#define DPB_AUX_CH_DATA2 0x64118
|
||||
|
@ -1618,7 +1635,7 @@
|
|||
#define I830_FIFO_LINE_SIZE 32
|
||||
#define I945_FIFO_SIZE 127 /* 945 & 965 */
|
||||
#define I915_FIFO_SIZE 95
|
||||
#define I855GM_FIFO_SIZE 255
|
||||
#define I855GM_FIFO_SIZE 127 /* In cachelines */
|
||||
#define I830_FIFO_SIZE 95
|
||||
#define I915_MAX_WM 0x3f
|
||||
|
||||
|
@ -1848,6 +1865,8 @@
|
|||
#define PFA_CTL_1 0x68080
|
||||
#define PFB_CTL_1 0x68880
|
||||
#define PF_ENABLE (1<<31)
|
||||
#define PFA_WIN_SZ 0x68074
|
||||
#define PFB_WIN_SZ 0x68874
|
||||
|
||||
/* legacy palette */
|
||||
#define LGC_PALETTE_A 0x4a000
|
||||
|
@ -2208,4 +2227,28 @@
|
|||
#define PCH_PP_OFF_DELAYS 0xc720c
|
||||
#define PCH_PP_DIVISOR 0xc7210
|
||||
|
||||
#define PCH_DP_B 0xe4100
|
||||
#define PCH_DPB_AUX_CH_CTL 0xe4110
|
||||
#define PCH_DPB_AUX_CH_DATA1 0xe4114
|
||||
#define PCH_DPB_AUX_CH_DATA2 0xe4118
|
||||
#define PCH_DPB_AUX_CH_DATA3 0xe411c
|
||||
#define PCH_DPB_AUX_CH_DATA4 0xe4120
|
||||
#define PCH_DPB_AUX_CH_DATA5 0xe4124
|
||||
|
||||
#define PCH_DP_C 0xe4200
|
||||
#define PCH_DPC_AUX_CH_CTL 0xe4210
|
||||
#define PCH_DPC_AUX_CH_DATA1 0xe4214
|
||||
#define PCH_DPC_AUX_CH_DATA2 0xe4218
|
||||
#define PCH_DPC_AUX_CH_DATA3 0xe421c
|
||||
#define PCH_DPC_AUX_CH_DATA4 0xe4220
|
||||
#define PCH_DPC_AUX_CH_DATA5 0xe4224
|
||||
|
||||
#define PCH_DP_D 0xe4300
|
||||
#define PCH_DPD_AUX_CH_CTL 0xe4310
|
||||
#define PCH_DPD_AUX_CH_DATA1 0xe4314
|
||||
#define PCH_DPD_AUX_CH_DATA2 0xe4318
|
||||
#define PCH_DPD_AUX_CH_DATA3 0xe431c
|
||||
#define PCH_DPD_AUX_CH_DATA4 0xe4320
|
||||
#define PCH_DPD_AUX_CH_DATA5 0xe4324
|
||||
|
||||
#endif /* _I915_REG_H_ */
|
||||
|
|
|
@ -598,7 +598,7 @@ int i915_restore_state(struct drm_device *dev)
|
|||
|
||||
for (i = 0; i < 16; i++) {
|
||||
I915_WRITE(SWF00 + (i << 2), dev_priv->saveSWF0[i]);
|
||||
I915_WRITE(SWF10 + (i << 2), dev_priv->saveSWF1[i+7]);
|
||||
I915_WRITE(SWF10 + (i << 2), dev_priv->saveSWF1[i]);
|
||||
}
|
||||
for (i = 0; i < 3; i++)
|
||||
I915_WRITE(SWF30 + (i << 2), dev_priv->saveSWF2[i]);
|
||||
|
|
|
@ -97,14 +97,13 @@ static void
|
|||
parse_lfp_panel_data(struct drm_i915_private *dev_priv,
|
||||
struct bdb_header *bdb)
|
||||
{
|
||||
struct drm_device *dev = dev_priv->dev;
|
||||
struct bdb_lvds_options *lvds_options;
|
||||
struct bdb_lvds_lfp_data *lvds_lfp_data;
|
||||
struct bdb_lvds_lfp_data_ptrs *lvds_lfp_data_ptrs;
|
||||
struct bdb_lvds_lfp_data_entry *entry;
|
||||
struct lvds_dvo_timing *dvo_timing;
|
||||
struct drm_display_mode *panel_fixed_mode;
|
||||
int lfp_data_size;
|
||||
int lfp_data_size, dvo_timing_offset;
|
||||
|
||||
/* Defaults if we can't find VBT info */
|
||||
dev_priv->lvds_dither = 0;
|
||||
|
@ -133,14 +132,16 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv,
|
|||
entry = (struct bdb_lvds_lfp_data_entry *)
|
||||
((uint8_t *)lvds_lfp_data->data + (lfp_data_size *
|
||||
lvds_options->panel_type));
|
||||
dvo_timing_offset = lvds_lfp_data_ptrs->ptr[0].dvo_timing_offset -
|
||||
lvds_lfp_data_ptrs->ptr[0].fp_timing_offset;
|
||||
|
||||
/* On IGDNG mobile, LVDS data block removes panel fitting registers.
|
||||
So dec 2 dword from dvo_timing offset */
|
||||
if (IS_IGDNG(dev))
|
||||
/*
|
||||
* the size of fp_timing varies on the different platform.
|
||||
* So calculate the DVO timing relative offset in LVDS data
|
||||
* entry to get the DVO timing entry
|
||||
*/
|
||||
dvo_timing = (struct lvds_dvo_timing *)
|
||||
((u8 *)&entry->dvo_timing - 8);
|
||||
else
|
||||
dvo_timing = &entry->dvo_timing;
|
||||
((unsigned char *)entry + dvo_timing_offset);
|
||||
|
||||
panel_fixed_mode = kzalloc(sizeof(*panel_fixed_mode), GFP_KERNEL);
|
||||
|
||||
|
@ -295,6 +296,25 @@ parse_sdvo_device_mapping(struct drm_i915_private *dev_priv,
|
|||
}
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
parse_driver_features(struct drm_i915_private *dev_priv,
|
||||
struct bdb_header *bdb)
|
||||
{
|
||||
struct drm_device *dev = dev_priv->dev;
|
||||
struct bdb_driver_features *driver;
|
||||
|
||||
/* set default for chips without eDP */
|
||||
if (!SUPPORTS_EDP(dev)) {
|
||||
dev_priv->edp_support = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
driver = find_section(bdb, BDB_DRIVER_FEATURES);
|
||||
if (driver && driver->lvds_config == BDB_DRIVER_FEATURE_EDP)
|
||||
dev_priv->edp_support = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* intel_init_bios - initialize VBIOS settings & find VBT
|
||||
* @dev: DRM device
|
||||
|
@ -345,6 +365,8 @@ intel_init_bios(struct drm_device *dev)
|
|||
parse_lfp_panel_data(dev_priv, bdb);
|
||||
parse_sdvo_panel_data(dev_priv, bdb);
|
||||
parse_sdvo_device_mapping(dev_priv, bdb);
|
||||
parse_driver_features(dev_priv, bdb);
|
||||
|
||||
pci_unmap_rom(pdev, bios);
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -381,6 +381,51 @@ struct bdb_sdvo_lvds_options {
|
|||
} __attribute__((packed));
|
||||
|
||||
|
||||
#define BDB_DRIVER_FEATURE_NO_LVDS 0
|
||||
#define BDB_DRIVER_FEATURE_INT_LVDS 1
|
||||
#define BDB_DRIVER_FEATURE_SDVO_LVDS 2
|
||||
#define BDB_DRIVER_FEATURE_EDP 3
|
||||
|
||||
struct bdb_driver_features {
|
||||
u8 boot_dev_algorithm:1;
|
||||
u8 block_display_switch:1;
|
||||
u8 allow_display_switch:1;
|
||||
u8 hotplug_dvo:1;
|
||||
u8 dual_view_zoom:1;
|
||||
u8 int15h_hook:1;
|
||||
u8 sprite_in_clone:1;
|
||||
u8 primary_lfp_id:1;
|
||||
|
||||
u16 boot_mode_x;
|
||||
u16 boot_mode_y;
|
||||
u8 boot_mode_bpp;
|
||||
u8 boot_mode_refresh;
|
||||
|
||||
u16 enable_lfp_primary:1;
|
||||
u16 selective_mode_pruning:1;
|
||||
u16 dual_frequency:1;
|
||||
u16 render_clock_freq:1; /* 0: high freq; 1: low freq */
|
||||
u16 nt_clone_support:1;
|
||||
u16 power_scheme_ui:1; /* 0: CUI; 1: 3rd party */
|
||||
u16 sprite_display_assign:1; /* 0: secondary; 1: primary */
|
||||
u16 cui_aspect_scaling:1;
|
||||
u16 preserve_aspect_ratio:1;
|
||||
u16 sdvo_device_power_down:1;
|
||||
u16 crt_hotplug:1;
|
||||
u16 lvds_config:2;
|
||||
u16 tv_hotplug:1;
|
||||
u16 hdmi_config:2;
|
||||
|
||||
u8 static_display:1;
|
||||
u8 reserved2:7;
|
||||
u16 legacy_crt_max_x;
|
||||
u16 legacy_crt_max_y;
|
||||
u8 legacy_crt_max_refresh;
|
||||
|
||||
u8 hdmi_termination;
|
||||
u8 custom_vbt_version;
|
||||
} __attribute__((packed));
|
||||
|
||||
bool intel_init_bios(struct drm_device *dev);
|
||||
|
||||
/*
|
||||
|
|
|
@ -156,6 +156,9 @@ static bool intel_igdng_crt_detect_hotplug(struct drm_connector *connector)
|
|||
|
||||
temp = adpa = I915_READ(PCH_ADPA);
|
||||
|
||||
adpa &= ~ADPA_DAC_ENABLE;
|
||||
I915_WRITE(PCH_ADPA, adpa);
|
||||
|
||||
adpa &= ~ADPA_CRT_HOTPLUG_MASK;
|
||||
|
||||
adpa |= (ADPA_CRT_HOTPLUG_PERIOD_128 |
|
||||
|
@ -169,13 +172,14 @@ static bool intel_igdng_crt_detect_hotplug(struct drm_connector *connector)
|
|||
DRM_DEBUG("pch crt adpa 0x%x", adpa);
|
||||
I915_WRITE(PCH_ADPA, adpa);
|
||||
|
||||
/* This might not be needed as not specified in spec...*/
|
||||
udelay(1000);
|
||||
while ((I915_READ(PCH_ADPA) & ADPA_CRT_HOTPLUG_FORCE_TRIGGER) != 0)
|
||||
;
|
||||
|
||||
/* Check the status to see if both blue and green are on now */
|
||||
adpa = I915_READ(PCH_ADPA);
|
||||
if ((adpa & ADPA_CRT_HOTPLUG_MONITOR_MASK) ==
|
||||
ADPA_CRT_HOTPLUG_MONITOR_COLOR)
|
||||
adpa &= ADPA_CRT_HOTPLUG_MONITOR_MASK;
|
||||
if ((adpa == ADPA_CRT_HOTPLUG_MONITOR_COLOR) ||
|
||||
(adpa == ADPA_CRT_HOTPLUG_MONITOR_MONO))
|
||||
ret = true;
|
||||
else
|
||||
ret = false;
|
||||
|
|
|
@ -34,6 +34,8 @@
|
|||
|
||||
#include "drm_crtc_helper.h"
|
||||
|
||||
#define HAS_eDP (intel_pipe_has_type(crtc, INTEL_OUTPUT_EDP))
|
||||
|
||||
bool intel_pipe_has_type (struct drm_crtc *crtc, int type);
|
||||
static void intel_update_watermarks(struct drm_device *dev);
|
||||
|
||||
|
@ -88,7 +90,7 @@ struct intel_limit {
|
|||
#define I8XX_P2_SLOW 4
|
||||
#define I8XX_P2_FAST 2
|
||||
#define I8XX_P2_LVDS_SLOW 14
|
||||
#define I8XX_P2_LVDS_FAST 14 /* No fast option */
|
||||
#define I8XX_P2_LVDS_FAST 7
|
||||
#define I8XX_P2_SLOW_LIMIT 165000
|
||||
|
||||
#define I9XX_DOT_MIN 20000
|
||||
|
@ -268,6 +270,9 @@ intel_igdng_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
|
|||
static bool
|
||||
intel_find_pll_g4x_dp(const intel_limit_t *, struct drm_crtc *crtc,
|
||||
int target, int refclk, intel_clock_t *best_clock);
|
||||
static bool
|
||||
intel_find_pll_igdng_dp(const intel_limit_t *, struct drm_crtc *crtc,
|
||||
int target, int refclk, intel_clock_t *best_clock);
|
||||
|
||||
static const intel_limit_t intel_limits_i8xx_dvo = {
|
||||
.dot = { .min = I8XX_DOT_MIN, .max = I8XX_DOT_MAX },
|
||||
|
@ -598,6 +603,23 @@ bool intel_pipe_has_type (struct drm_crtc *crtc, int type)
|
|||
return false;
|
||||
}
|
||||
|
||||
struct drm_connector *
|
||||
intel_pipe_get_output (struct drm_crtc *crtc)
|
||||
{
|
||||
struct drm_device *dev = crtc->dev;
|
||||
struct drm_mode_config *mode_config = &dev->mode_config;
|
||||
struct drm_connector *l_entry, *ret = NULL;
|
||||
|
||||
list_for_each_entry(l_entry, &mode_config->connector_list, head) {
|
||||
if (l_entry->encoder &&
|
||||
l_entry->encoder->crtc == crtc) {
|
||||
ret = l_entry;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define INTELPllInvalid(s) do { /* DRM_DEBUG(s); */ return false; } while (0)
|
||||
/**
|
||||
* Returns whether the given set of divisors are valid for a given refclk with
|
||||
|
@ -645,7 +667,7 @@ intel_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
|
|||
int err = target;
|
||||
|
||||
if (IS_I9XX(dev) && intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) &&
|
||||
(I915_READ(LVDS) & LVDS_PORT_EN) != 0) {
|
||||
(I915_READ(LVDS)) != 0) {
|
||||
/*
|
||||
* For LVDS, if the panel is on, just rely on its current
|
||||
* settings for dual-channel. We haven't figured out how to
|
||||
|
@ -751,6 +773,30 @@ intel_g4x_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
|
|||
return found;
|
||||
}
|
||||
|
||||
static bool
|
||||
intel_find_pll_igdng_dp(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;
|
||||
if (target < 200000) {
|
||||
clock.n = 1;
|
||||
clock.p1 = 2;
|
||||
clock.p2 = 10;
|
||||
clock.m1 = 12;
|
||||
clock.m2 = 9;
|
||||
} else {
|
||||
clock.n = 2;
|
||||
clock.p1 = 1;
|
||||
clock.p2 = 10;
|
||||
clock.m1 = 14;
|
||||
clock.m2 = 8;
|
||||
}
|
||||
intel_clock(dev, refclk, &clock);
|
||||
memcpy(best_clock, &clock, sizeof(intel_clock_t));
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
intel_igdng_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
|
||||
int target, int refclk, intel_clock_t *best_clock)
|
||||
|
@ -763,6 +809,14 @@ intel_igdng_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
|
|||
int err_most = 47;
|
||||
found = false;
|
||||
|
||||
/* eDP has only 2 clock choice, no n/m/p setting */
|
||||
if (HAS_eDP)
|
||||
return true;
|
||||
|
||||
if (intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT))
|
||||
return intel_find_pll_igdng_dp(limit, crtc, target,
|
||||
refclk, best_clock);
|
||||
|
||||
if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) {
|
||||
if ((I915_READ(LVDS) & LVDS_CLKB_POWER_MASK) ==
|
||||
LVDS_CLKB_POWER_UP)
|
||||
|
@ -998,6 +1052,90 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* Disable the VGA plane that we never use */
|
||||
static void i915_disable_vga (struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
u8 sr1;
|
||||
u32 vga_reg;
|
||||
|
||||
if (IS_IGDNG(dev))
|
||||
vga_reg = CPU_VGACNTRL;
|
||||
else
|
||||
vga_reg = VGACNTRL;
|
||||
|
||||
if (I915_READ(vga_reg) & VGA_DISP_DISABLE)
|
||||
return;
|
||||
|
||||
I915_WRITE8(VGA_SR_INDEX, 1);
|
||||
sr1 = I915_READ8(VGA_SR_DATA);
|
||||
I915_WRITE8(VGA_SR_DATA, sr1 | (1 << 5));
|
||||
udelay(100);
|
||||
|
||||
I915_WRITE(vga_reg, VGA_DISP_DISABLE);
|
||||
}
|
||||
|
||||
static void igdng_disable_pll_edp (struct drm_crtc *crtc)
|
||||
{
|
||||
struct drm_device *dev = crtc->dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
u32 dpa_ctl;
|
||||
|
||||
DRM_DEBUG("\n");
|
||||
dpa_ctl = I915_READ(DP_A);
|
||||
dpa_ctl &= ~DP_PLL_ENABLE;
|
||||
I915_WRITE(DP_A, dpa_ctl);
|
||||
}
|
||||
|
||||
static void igdng_enable_pll_edp (struct drm_crtc *crtc)
|
||||
{
|
||||
struct drm_device *dev = crtc->dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
u32 dpa_ctl;
|
||||
|
||||
dpa_ctl = I915_READ(DP_A);
|
||||
dpa_ctl |= DP_PLL_ENABLE;
|
||||
I915_WRITE(DP_A, dpa_ctl);
|
||||
udelay(200);
|
||||
}
|
||||
|
||||
|
||||
static void igdng_set_pll_edp (struct drm_crtc *crtc, int clock)
|
||||
{
|
||||
struct drm_device *dev = crtc->dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
u32 dpa_ctl;
|
||||
|
||||
DRM_DEBUG("eDP PLL enable for clock %d\n", clock);
|
||||
dpa_ctl = I915_READ(DP_A);
|
||||
dpa_ctl &= ~DP_PLL_FREQ_MASK;
|
||||
|
||||
if (clock < 200000) {
|
||||
u32 temp;
|
||||
dpa_ctl |= DP_PLL_FREQ_160MHZ;
|
||||
/* workaround for 160Mhz:
|
||||
1) program 0x4600c bits 15:0 = 0x8124
|
||||
2) program 0x46010 bit 0 = 1
|
||||
3) program 0x46034 bit 24 = 1
|
||||
4) program 0x64000 bit 14 = 1
|
||||
*/
|
||||
temp = I915_READ(0x4600c);
|
||||
temp &= 0xffff0000;
|
||||
I915_WRITE(0x4600c, temp | 0x8124);
|
||||
|
||||
temp = I915_READ(0x46010);
|
||||
I915_WRITE(0x46010, temp | 1);
|
||||
|
||||
temp = I915_READ(0x46034);
|
||||
I915_WRITE(0x46034, temp | (1 << 24));
|
||||
} else {
|
||||
dpa_ctl |= DP_PLL_FREQ_270MHZ;
|
||||
}
|
||||
I915_WRITE(DP_A, dpa_ctl);
|
||||
|
||||
udelay(500);
|
||||
}
|
||||
|
||||
static void igdng_crtc_dpms(struct drm_crtc *crtc, int mode)
|
||||
{
|
||||
struct drm_device *dev = crtc->dev;
|
||||
|
@ -1015,6 +1153,7 @@ static void igdng_crtc_dpms(struct drm_crtc *crtc, int mode)
|
|||
int fdi_rx_imr_reg = (pipe == 0) ? FDI_RXA_IMR : FDI_RXB_IMR;
|
||||
int transconf_reg = (pipe == 0) ? TRANSACONF : TRANSBCONF;
|
||||
int pf_ctl_reg = (pipe == 0) ? PFA_CTL_1 : PFB_CTL_1;
|
||||
int pf_win_size = (pipe == 0) ? PFA_WIN_SZ : PFB_WIN_SZ;
|
||||
int cpu_htot_reg = (pipe == 0) ? HTOTAL_A : HTOTAL_B;
|
||||
int cpu_hblank_reg = (pipe == 0) ? HBLANK_A : HBLANK_B;
|
||||
int cpu_hsync_reg = (pipe == 0) ? HSYNC_A : HSYNC_B;
|
||||
|
@ -1028,7 +1167,7 @@ static void igdng_crtc_dpms(struct drm_crtc *crtc, int mode)
|
|||
int trans_vblank_reg = (pipe == 0) ? TRANS_VBLANK_A : TRANS_VBLANK_B;
|
||||
int trans_vsync_reg = (pipe == 0) ? TRANS_VSYNC_A : TRANS_VSYNC_B;
|
||||
u32 temp;
|
||||
int tries = 5, j;
|
||||
int tries = 5, j, n;
|
||||
|
||||
/* XXX: When our outputs are all unaware of DPMS modes other than off
|
||||
* and on, we should map those modes to DRM_MODE_DPMS_OFF in the CRTC.
|
||||
|
@ -1038,6 +1177,10 @@ static void igdng_crtc_dpms(struct drm_crtc *crtc, int mode)
|
|||
case DRM_MODE_DPMS_STANDBY:
|
||||
case DRM_MODE_DPMS_SUSPEND:
|
||||
DRM_DEBUG("crtc %d dpms on\n", pipe);
|
||||
if (HAS_eDP) {
|
||||
/* enable eDP PLL */
|
||||
igdng_enable_pll_edp(crtc);
|
||||
} else {
|
||||
/* enable PCH DPLL */
|
||||
temp = I915_READ(pch_dpll_reg);
|
||||
if ((temp & DPLL_VCO_ENABLE) == 0) {
|
||||
|
@ -1060,6 +1203,7 @@ static void igdng_crtc_dpms(struct drm_crtc *crtc, int mode)
|
|||
I915_READ(fdi_tx_reg);
|
||||
udelay(100);
|
||||
}
|
||||
}
|
||||
|
||||
/* Enable CPU pipe */
|
||||
temp = I915_READ(pipeconf_reg);
|
||||
|
@ -1077,6 +1221,7 @@ static void igdng_crtc_dpms(struct drm_crtc *crtc, int mode)
|
|||
I915_WRITE(dspbase_reg, I915_READ(dspbase_reg));
|
||||
}
|
||||
|
||||
if (!HAS_eDP) {
|
||||
/* enable CPU FDI TX and PCH FDI RX */
|
||||
temp = I915_READ(fdi_tx_reg);
|
||||
temp |= FDI_TX_ENABLE;
|
||||
|
@ -1155,7 +1300,8 @@ static void igdng_crtc_dpms(struct drm_crtc *crtc, int mode)
|
|||
} else
|
||||
DRM_DEBUG("train 2 fail\n");
|
||||
} else {
|
||||
I915_WRITE(fdi_rx_iir_reg, temp | FDI_RX_SYMBOL_LOCK);
|
||||
I915_WRITE(fdi_rx_iir_reg,
|
||||
temp | FDI_RX_SYMBOL_LOCK);
|
||||
DRM_DEBUG("train 2 ok 2!\n");
|
||||
}
|
||||
DRM_DEBUG("train done\n");
|
||||
|
@ -1194,14 +1340,15 @@ static void igdng_crtc_dpms(struct drm_crtc *crtc, int mode)
|
|||
/* wait one idle pattern time */
|
||||
udelay(100);
|
||||
|
||||
}
|
||||
|
||||
intel_crtc_load_lut(crtc);
|
||||
|
||||
break;
|
||||
case DRM_MODE_DPMS_OFF:
|
||||
DRM_DEBUG("crtc %d dpms off\n", pipe);
|
||||
|
||||
/* Disable the VGA plane that we never use */
|
||||
I915_WRITE(CPU_VGACNTRL, VGA_DISP_DISABLE);
|
||||
i915_disable_vga(dev);
|
||||
|
||||
/* Disable display plane */
|
||||
temp = I915_READ(dspcntr_reg);
|
||||
|
@ -1217,17 +1364,23 @@ static void igdng_crtc_dpms(struct drm_crtc *crtc, int mode)
|
|||
if ((temp & PIPEACONF_ENABLE) != 0) {
|
||||
I915_WRITE(pipeconf_reg, temp & ~PIPEACONF_ENABLE);
|
||||
I915_READ(pipeconf_reg);
|
||||
n = 0;
|
||||
/* wait for cpu pipe off, pipe state */
|
||||
while ((I915_READ(pipeconf_reg) & I965_PIPECONF_ACTIVE) != 0)
|
||||
;
|
||||
while ((I915_READ(pipeconf_reg) & I965_PIPECONF_ACTIVE) != 0) {
|
||||
n++;
|
||||
if (n < 60) {
|
||||
udelay(500);
|
||||
continue;
|
||||
} else {
|
||||
DRM_DEBUG("pipe %d off delay\n", pipe);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else
|
||||
DRM_DEBUG("crtc %d is disabled\n", pipe);
|
||||
|
||||
/* IGDNG-A : disable cpu panel fitter ? */
|
||||
temp = I915_READ(pf_ctl_reg);
|
||||
if ((temp & PF_ENABLE) != 0) {
|
||||
I915_WRITE(pf_ctl_reg, temp & ~PF_ENABLE);
|
||||
I915_READ(pf_ctl_reg);
|
||||
if (HAS_eDP) {
|
||||
igdng_disable_pll_edp(crtc);
|
||||
}
|
||||
|
||||
/* disable CPU FDI tx and PCH FDI rx */
|
||||
|
@ -1239,6 +1392,8 @@ static void igdng_crtc_dpms(struct drm_crtc *crtc, int mode)
|
|||
I915_WRITE(fdi_rx_reg, temp & ~FDI_RX_ENABLE);
|
||||
I915_READ(fdi_rx_reg);
|
||||
|
||||
udelay(100);
|
||||
|
||||
/* still set train pattern 1 */
|
||||
temp = I915_READ(fdi_tx_reg);
|
||||
temp &= ~FDI_LINK_TRAIN_NONE;
|
||||
|
@ -1250,14 +1405,25 @@ static void igdng_crtc_dpms(struct drm_crtc *crtc, int mode)
|
|||
temp |= FDI_LINK_TRAIN_PATTERN_1;
|
||||
I915_WRITE(fdi_rx_reg, temp);
|
||||
|
||||
udelay(100);
|
||||
|
||||
/* disable PCH transcoder */
|
||||
temp = I915_READ(transconf_reg);
|
||||
if ((temp & TRANS_ENABLE) != 0) {
|
||||
I915_WRITE(transconf_reg, temp & ~TRANS_ENABLE);
|
||||
I915_READ(transconf_reg);
|
||||
n = 0;
|
||||
/* wait for PCH transcoder off, transcoder state */
|
||||
while ((I915_READ(transconf_reg) & TRANS_STATE_ENABLE) != 0)
|
||||
;
|
||||
while ((I915_READ(transconf_reg) & TRANS_STATE_ENABLE) != 0) {
|
||||
n++;
|
||||
if (n < 60) {
|
||||
udelay(500);
|
||||
continue;
|
||||
} else {
|
||||
DRM_DEBUG("transcoder %d off delay\n", pipe);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* disable PCH DPLL */
|
||||
|
@ -1275,6 +1441,22 @@ static void igdng_crtc_dpms(struct drm_crtc *crtc, int mode)
|
|||
I915_READ(fdi_rx_reg);
|
||||
}
|
||||
|
||||
/* Disable CPU FDI TX PLL */
|
||||
temp = I915_READ(fdi_tx_reg);
|
||||
if ((temp & FDI_TX_PLL_ENABLE) != 0) {
|
||||
I915_WRITE(fdi_tx_reg, temp & ~FDI_TX_PLL_ENABLE);
|
||||
I915_READ(fdi_tx_reg);
|
||||
udelay(100);
|
||||
}
|
||||
|
||||
/* Disable PF */
|
||||
temp = I915_READ(pf_ctl_reg);
|
||||
if ((temp & PF_ENABLE) != 0) {
|
||||
I915_WRITE(pf_ctl_reg, temp & ~PF_ENABLE);
|
||||
I915_READ(pf_ctl_reg);
|
||||
}
|
||||
I915_WRITE(pf_win_size, 0);
|
||||
|
||||
/* Wait for the clocks to turn off. */
|
||||
udelay(150);
|
||||
break;
|
||||
|
@ -1342,7 +1524,7 @@ static void i9xx_crtc_dpms(struct drm_crtc *crtc, int mode)
|
|||
//intel_crtc_dpms_video(crtc, FALSE); TODO
|
||||
|
||||
/* Disable the VGA plane that we never use */
|
||||
I915_WRITE(VGACNTRL, VGA_DISP_DISABLE);
|
||||
i915_disable_vga(dev);
|
||||
|
||||
/* Disable display plane */
|
||||
temp = I915_READ(dspcntr_reg);
|
||||
|
@ -1623,48 +1805,72 @@ static struct intel_watermark_params igd_cursor_hplloff_wm = {
|
|||
IGD_FIFO_LINE_SIZE
|
||||
};
|
||||
static struct intel_watermark_params i945_wm_info = {
|
||||
I915_FIFO_LINE_SIZE,
|
||||
I915_MAX_WM,
|
||||
1,
|
||||
0,
|
||||
IGD_FIFO_LINE_SIZE
|
||||
};
|
||||
static struct intel_watermark_params i915_wm_info = {
|
||||
I945_FIFO_SIZE,
|
||||
I915_MAX_WM,
|
||||
1,
|
||||
0,
|
||||
2,
|
||||
I915_FIFO_LINE_SIZE
|
||||
};
|
||||
static struct intel_watermark_params i915_wm_info = {
|
||||
I915_FIFO_SIZE,
|
||||
I915_MAX_WM,
|
||||
1,
|
||||
2,
|
||||
I915_FIFO_LINE_SIZE
|
||||
};
|
||||
static struct intel_watermark_params i855_wm_info = {
|
||||
I855GM_FIFO_SIZE,
|
||||
I915_MAX_WM,
|
||||
1,
|
||||
0,
|
||||
2,
|
||||
I830_FIFO_LINE_SIZE
|
||||
};
|
||||
static struct intel_watermark_params i830_wm_info = {
|
||||
I830_FIFO_SIZE,
|
||||
I915_MAX_WM,
|
||||
1,
|
||||
0,
|
||||
2,
|
||||
I830_FIFO_LINE_SIZE
|
||||
};
|
||||
|
||||
/**
|
||||
* intel_calculate_wm - calculate watermark level
|
||||
* @clock_in_khz: pixel clock
|
||||
* @wm: chip FIFO params
|
||||
* @pixel_size: display pixel size
|
||||
* @latency_ns: memory latency for the platform
|
||||
*
|
||||
* Calculate the watermark level (the level at which the display plane will
|
||||
* start fetching from memory again). Each chip has a different display
|
||||
* FIFO size and allocation, so the caller needs to figure that out and pass
|
||||
* in the correct intel_watermark_params structure.
|
||||
*
|
||||
* As the pixel clock runs, the FIFO will be drained at a rate that depends
|
||||
* on the pixel size. When it reaches the watermark level, it'll start
|
||||
* fetching FIFO line sized based chunks from memory until the FIFO fills
|
||||
* past the watermark point. If the FIFO drains completely, a FIFO underrun
|
||||
* will occur, and a display engine hang could result.
|
||||
*/
|
||||
static unsigned long intel_calculate_wm(unsigned long clock_in_khz,
|
||||
struct intel_watermark_params *wm,
|
||||
int pixel_size,
|
||||
unsigned long latency_ns)
|
||||
{
|
||||
unsigned long bytes_required, wm_size;
|
||||
long entries_required, wm_size;
|
||||
|
||||
bytes_required = (clock_in_khz * pixel_size * latency_ns) / 1000000;
|
||||
bytes_required /= wm->cacheline_size;
|
||||
wm_size = wm->fifo_size - bytes_required - wm->guard_size;
|
||||
entries_required = (clock_in_khz * pixel_size * latency_ns) / 1000000;
|
||||
entries_required /= wm->cacheline_size;
|
||||
|
||||
if (wm_size > wm->max_wm)
|
||||
DRM_DEBUG("FIFO entries required for mode: %d\n", entries_required);
|
||||
|
||||
wm_size = wm->fifo_size - (entries_required + wm->guard_size);
|
||||
|
||||
DRM_DEBUG("FIFO watermark level: %d\n", wm_size);
|
||||
|
||||
/* Don't promote wm_size to unsigned... */
|
||||
if (wm_size > (long)wm->max_wm)
|
||||
wm_size = wm->max_wm;
|
||||
if (wm_size == 0)
|
||||
if (wm_size <= 0)
|
||||
wm_size = wm->default_wm;
|
||||
return wm_size;
|
||||
}
|
||||
|
@ -1799,8 +2005,40 @@ static void igd_enable_cxsr(struct drm_device *dev, unsigned long clock,
|
|||
return;
|
||||
}
|
||||
|
||||
const static int latency_ns = 5000; /* default for non-igd platforms */
|
||||
const static int latency_ns = 3000; /* default for non-igd platforms */
|
||||
|
||||
static int intel_get_fifo_size(struct drm_device *dev, int plane)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
uint32_t dsparb = I915_READ(DSPARB);
|
||||
int size;
|
||||
|
||||
if (IS_I9XX(dev)) {
|
||||
if (plane == 0)
|
||||
size = dsparb & 0x7f;
|
||||
else
|
||||
size = ((dsparb >> DSPARB_CSTART_SHIFT) & 0x7f) -
|
||||
(dsparb & 0x7f);
|
||||
} else if (IS_I85X(dev)) {
|
||||
if (plane == 0)
|
||||
size = dsparb & 0x1ff;
|
||||
else
|
||||
size = ((dsparb >> DSPARB_BEND_SHIFT) & 0x1ff) -
|
||||
(dsparb & 0x1ff);
|
||||
size >>= 1; /* Convert to cachelines */
|
||||
} else if (IS_845G(dev)) {
|
||||
size = dsparb & 0x7f;
|
||||
size >>= 2; /* Convert to cachelines */
|
||||
} else {
|
||||
size = dsparb & 0x7f;
|
||||
size >>= 1; /* Convert to cachelines */
|
||||
}
|
||||
|
||||
DRM_DEBUG("FIFO size - (0x%08x) %s: %d\n", dsparb, plane ? "B" : "A",
|
||||
size);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static void i965_update_wm(struct drm_device *dev)
|
||||
{
|
||||
|
@ -1817,101 +2055,89 @@ static void i9xx_update_wm(struct drm_device *dev, int planea_clock,
|
|||
int planeb_clock, int sr_hdisplay, int pixel_size)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
uint32_t fwater_lo = I915_READ(FW_BLC) & MM_FIFO_WATERMARK;
|
||||
uint32_t fwater_hi = I915_READ(FW_BLC2) & LM_FIFO_WATERMARK;
|
||||
int bsize, asize, cwm, bwm = 1, awm = 1, srwm = 1;
|
||||
uint32_t dsparb = I915_READ(DSPARB);
|
||||
int planea_entries, planeb_entries;
|
||||
struct intel_watermark_params *wm_params;
|
||||
uint32_t fwater_lo;
|
||||
uint32_t fwater_hi;
|
||||
int total_size, cacheline_size, cwm, srwm = 1;
|
||||
int planea_wm, planeb_wm;
|
||||
struct intel_watermark_params planea_params, planeb_params;
|
||||
unsigned long line_time_us;
|
||||
int sr_clock, sr_entries = 0;
|
||||
|
||||
/* Create copies of the base settings for each pipe */
|
||||
if (IS_I965GM(dev) || IS_I945GM(dev))
|
||||
wm_params = &i945_wm_info;
|
||||
planea_params = planeb_params = i945_wm_info;
|
||||
else if (IS_I9XX(dev))
|
||||
wm_params = &i915_wm_info;
|
||||
planea_params = planeb_params = i915_wm_info;
|
||||
else
|
||||
wm_params = &i855_wm_info;
|
||||
planea_params = planeb_params = i855_wm_info;
|
||||
|
||||
planea_entries = intel_calculate_wm(planea_clock, wm_params,
|
||||
/* Grab a couple of global values before we overwrite them */
|
||||
total_size = planea_params.fifo_size;
|
||||
cacheline_size = planea_params.cacheline_size;
|
||||
|
||||
/* Update per-plane FIFO sizes */
|
||||
planea_params.fifo_size = intel_get_fifo_size(dev, 0);
|
||||
planeb_params.fifo_size = intel_get_fifo_size(dev, 1);
|
||||
|
||||
planea_wm = intel_calculate_wm(planea_clock, &planea_params,
|
||||
pixel_size, latency_ns);
|
||||
planeb_entries = intel_calculate_wm(planeb_clock, wm_params,
|
||||
planeb_wm = intel_calculate_wm(planeb_clock, &planeb_params,
|
||||
pixel_size, latency_ns);
|
||||
|
||||
DRM_DEBUG("FIFO entries - A: %d, B: %d\n", planea_entries,
|
||||
planeb_entries);
|
||||
|
||||
if (IS_I9XX(dev)) {
|
||||
asize = dsparb & 0x7f;
|
||||
bsize = (dsparb >> DSPARB_CSTART_SHIFT) & 0x7f;
|
||||
} else {
|
||||
asize = dsparb & 0x1ff;
|
||||
bsize = (dsparb >> DSPARB_BEND_SHIFT) & 0x1ff;
|
||||
}
|
||||
DRM_DEBUG("FIFO size - A: %d, B: %d\n", asize, bsize);
|
||||
|
||||
/* Two extra entries for padding */
|
||||
awm = asize - (planea_entries + 2);
|
||||
bwm = bsize - (planeb_entries + 2);
|
||||
|
||||
/* Sanity check against potentially bad FIFO allocations */
|
||||
if (awm <= 0) {
|
||||
/* pipe is on but has too few FIFO entries */
|
||||
if (planea_entries != 0)
|
||||
DRM_DEBUG("plane A needs more FIFO entries\n");
|
||||
awm = 1;
|
||||
}
|
||||
if (bwm <= 0) {
|
||||
if (planeb_entries != 0)
|
||||
DRM_DEBUG("plane B needs more FIFO entries\n");
|
||||
bwm = 1;
|
||||
}
|
||||
DRM_DEBUG("FIFO watermarks - A: %d, B: %d\n", planea_wm, planeb_wm);
|
||||
|
||||
/*
|
||||
* Overlay gets an aggressive default since video jitter is bad.
|
||||
*/
|
||||
cwm = 2;
|
||||
|
||||
/* Calc sr entries for one pipe configs */
|
||||
if (!planea_clock || !planeb_clock) {
|
||||
/* Calc sr entries for one plane configs */
|
||||
if (sr_hdisplay && (!planea_clock || !planeb_clock)) {
|
||||
/* self-refresh has much higher latency */
|
||||
const static int sr_latency_ns = 6000;
|
||||
|
||||
sr_clock = planea_clock ? planea_clock : planeb_clock;
|
||||
line_time_us = (sr_hdisplay * 1000) / sr_clock;
|
||||
sr_entries = (((latency_ns / line_time_us) + 1) * pixel_size *
|
||||
sr_hdisplay) / 1000;
|
||||
sr_entries = roundup(sr_entries / wm_params->cacheline_size, 1);
|
||||
if (sr_entries < wm_params->fifo_size)
|
||||
srwm = wm_params->fifo_size - sr_entries;
|
||||
line_time_us = ((sr_hdisplay * 1000) / sr_clock);
|
||||
|
||||
/* Use ns/us then divide to preserve precision */
|
||||
sr_entries = (((sr_latency_ns / line_time_us) + 1) *
|
||||
pixel_size * sr_hdisplay) / 1000;
|
||||
sr_entries = roundup(sr_entries / cacheline_size, 1);
|
||||
DRM_DEBUG("self-refresh entries: %d\n", sr_entries);
|
||||
srwm = total_size - sr_entries;
|
||||
if (srwm < 0)
|
||||
srwm = 1;
|
||||
if (IS_I9XX(dev))
|
||||
I915_WRITE(FW_BLC_SELF, (srwm & 0x3f));
|
||||
}
|
||||
|
||||
DRM_DEBUG("Setting FIFO watermarks - A: %d, B: %d, C: %d, SR %d\n",
|
||||
awm, bwm, cwm, srwm);
|
||||
planea_wm, planeb_wm, cwm, srwm);
|
||||
|
||||
fwater_lo = fwater_lo | ((bwm & 0x3f) << 16) | (awm & 0x3f);
|
||||
fwater_hi = fwater_hi | (cwm & 0x1f);
|
||||
fwater_lo = ((planeb_wm & 0x3f) << 16) | (planea_wm & 0x3f);
|
||||
fwater_hi = (cwm & 0x1f);
|
||||
|
||||
/* Set request length to 8 cachelines per fetch */
|
||||
fwater_lo = fwater_lo | (1 << 24) | (1 << 8);
|
||||
fwater_hi = fwater_hi | (1 << 8);
|
||||
|
||||
I915_WRITE(FW_BLC, fwater_lo);
|
||||
I915_WRITE(FW_BLC2, fwater_hi);
|
||||
if (IS_I9XX(dev))
|
||||
I915_WRITE(FW_BLC_SELF, FW_BLC_SELF_EN | (srwm & 0x3f));
|
||||
}
|
||||
|
||||
static void i830_update_wm(struct drm_device *dev, int planea_clock,
|
||||
int pixel_size)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
uint32_t dsparb = I915_READ(DSPARB);
|
||||
uint32_t fwater_lo = I915_READ(FW_BLC) & MM_FIFO_WATERMARK;
|
||||
unsigned int asize, awm;
|
||||
int planea_entries;
|
||||
uint32_t fwater_lo = I915_READ(FW_BLC) & ~0xfff;
|
||||
int planea_wm;
|
||||
|
||||
planea_entries = intel_calculate_wm(planea_clock, &i830_wm_info,
|
||||
i830_wm_info.fifo_size = intel_get_fifo_size(dev, 0);
|
||||
|
||||
planea_wm = intel_calculate_wm(planea_clock, &i830_wm_info,
|
||||
pixel_size, latency_ns);
|
||||
fwater_lo |= (3<<8) | planea_wm;
|
||||
|
||||
asize = dsparb & 0x7f;
|
||||
|
||||
awm = asize - planea_entries;
|
||||
|
||||
fwater_lo = fwater_lo | awm;
|
||||
DRM_DEBUG("Setting FIFO watermarks - A: %d\n", planea_wm);
|
||||
|
||||
I915_WRITE(FW_BLC, fwater_lo);
|
||||
}
|
||||
|
@ -1984,7 +2210,7 @@ static void intel_update_watermarks(struct drm_device *dev)
|
|||
if (enabled <= 0)
|
||||
return;
|
||||
|
||||
/* Single pipe configs can enable self refresh */
|
||||
/* Single plane configs can enable self refresh */
|
||||
if (enabled == 1 && IS_IGD(dev))
|
||||
igd_enable_cxsr(dev, sr_clock, pixel_size);
|
||||
else if (IS_IGD(dev))
|
||||
|
@ -2028,6 +2254,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
|
|||
u32 dpll = 0, fp = 0, dspcntr, pipeconf;
|
||||
bool ok, 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;
|
||||
struct drm_connector *connector;
|
||||
const intel_limit_t *limit;
|
||||
|
@ -2043,6 +2270,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
|
|||
int lvds_reg = LVDS;
|
||||
u32 temp;
|
||||
int sdvo_pixel_multiply;
|
||||
int target_clock;
|
||||
|
||||
drm_vblank_pre_modeset(dev, pipe);
|
||||
|
||||
|
@ -2074,6 +2302,9 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
|
|||
case INTEL_OUTPUT_DISPLAYPORT:
|
||||
is_dp = true;
|
||||
break;
|
||||
case INTEL_OUTPUT_EDP:
|
||||
is_edp = true;
|
||||
break;
|
||||
}
|
||||
|
||||
num_outputs++;
|
||||
|
@ -2125,11 +2356,29 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
|
|||
}
|
||||
|
||||
/* FDI link */
|
||||
if (IS_IGDNG(dev))
|
||||
igdng_compute_m_n(3, 4, /* lane num 4 */
|
||||
adjusted_mode->clock,
|
||||
270000, /* lane clock */
|
||||
&m_n);
|
||||
if (IS_IGDNG(dev)) {
|
||||
int lane, link_bw;
|
||||
/* eDP doesn't require FDI link, so just set DP M/N
|
||||
according to current link config */
|
||||
if (is_edp) {
|
||||
struct drm_connector *edp;
|
||||
target_clock = mode->clock;
|
||||
edp = intel_pipe_get_output(crtc);
|
||||
intel_edp_link_config(to_intel_output(edp),
|
||||
&lane, &link_bw);
|
||||
} else {
|
||||
/* DP over FDI requires target mode clock
|
||||
instead of link clock */
|
||||
if (is_dp)
|
||||
target_clock = mode->clock;
|
||||
else
|
||||
target_clock = adjusted_mode->clock;
|
||||
lane = 4;
|
||||
link_bw = 270000;
|
||||
}
|
||||
igdng_compute_m_n(3, lane, target_clock,
|
||||
link_bw, &m_n);
|
||||
}
|
||||
|
||||
if (IS_IGD(dev))
|
||||
fp = (1 << clock.n) << 16 | clock.m1 << 8 | clock.m2;
|
||||
|
@ -2250,29 +2499,15 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
|
|||
dpll_reg = pch_dpll_reg;
|
||||
}
|
||||
|
||||
if (dpll & DPLL_VCO_ENABLE) {
|
||||
if (is_edp) {
|
||||
igdng_disable_pll_edp(crtc);
|
||||
} else if ((dpll & DPLL_VCO_ENABLE)) {
|
||||
I915_WRITE(fp_reg, fp);
|
||||
I915_WRITE(dpll_reg, dpll & ~DPLL_VCO_ENABLE);
|
||||
I915_READ(dpll_reg);
|
||||
udelay(150);
|
||||
}
|
||||
|
||||
if (IS_IGDNG(dev)) {
|
||||
/* enable PCH clock reference source */
|
||||
/* XXX need to change the setting for other outputs */
|
||||
u32 temp;
|
||||
temp = I915_READ(PCH_DREF_CONTROL);
|
||||
temp &= ~DREF_NONSPREAD_SOURCE_MASK;
|
||||
temp |= DREF_NONSPREAD_CK505_ENABLE;
|
||||
temp &= ~DREF_SSC_SOURCE_MASK;
|
||||
temp |= DREF_SSC_SOURCE_ENABLE;
|
||||
temp &= ~DREF_SSC1_ENABLE;
|
||||
/* if no eDP, disable source output to CPU */
|
||||
temp &= ~DREF_CPU_SOURCE_OUTPUT_MASK;
|
||||
temp |= DREF_CPU_SOURCE_OUTPUT_DISABLE;
|
||||
I915_WRITE(PCH_DREF_CONTROL, temp);
|
||||
}
|
||||
|
||||
/* The LVDS pin pair needs to be on before the DPLLs are enabled.
|
||||
* This is an exception to the general rule that mode_set doesn't turn
|
||||
* things on.
|
||||
|
@ -2304,6 +2539,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
|
|||
if (is_dp)
|
||||
intel_dp_set_m_n(crtc, mode, adjusted_mode);
|
||||
|
||||
if (!is_edp) {
|
||||
I915_WRITE(fp_reg, fp);
|
||||
I915_WRITE(dpll_reg, dpll);
|
||||
I915_READ(dpll_reg);
|
||||
|
@ -2321,6 +2557,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
|
|||
I915_READ(dpll_reg);
|
||||
/* Wait for the clocks to stabilize. */
|
||||
udelay(150);
|
||||
}
|
||||
|
||||
I915_WRITE(htot_reg, (adjusted_mode->crtc_hdisplay - 1) |
|
||||
((adjusted_mode->crtc_htotal - 1) << 16));
|
||||
|
@ -2350,11 +2587,15 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
|
|||
I915_WRITE(link_m1_reg, m_n.link_m);
|
||||
I915_WRITE(link_n1_reg, m_n.link_n);
|
||||
|
||||
if (is_edp) {
|
||||
igdng_set_pll_edp(crtc, adjusted_mode->clock);
|
||||
} else {
|
||||
/* enable FDI RX PLL too */
|
||||
temp = I915_READ(fdi_rx_reg);
|
||||
I915_WRITE(fdi_rx_reg, temp | FDI_RX_PLL_ENABLE);
|
||||
udelay(200);
|
||||
}
|
||||
}
|
||||
|
||||
I915_WRITE(pipeconf_reg, pipeconf);
|
||||
I915_READ(pipeconf_reg);
|
||||
|
@ -2951,12 +3192,17 @@ static void intel_setup_outputs(struct drm_device *dev)
|
|||
if (IS_IGDNG(dev)) {
|
||||
int found;
|
||||
|
||||
if (IS_MOBILE(dev) && (I915_READ(DP_A) & DP_DETECTED))
|
||||
intel_dp_init(dev, DP_A);
|
||||
|
||||
if (I915_READ(HDMIB) & PORT_DETECTED) {
|
||||
/* check SDVOB */
|
||||
/* found = intel_sdvo_init(dev, HDMIB); */
|
||||
found = 0;
|
||||
if (!found)
|
||||
intel_hdmi_init(dev, HDMIB);
|
||||
if (!found && (I915_READ(PCH_DP_B) & DP_DETECTED))
|
||||
intel_dp_init(dev, PCH_DP_B);
|
||||
}
|
||||
|
||||
if (I915_READ(HDMIC) & PORT_DETECTED)
|
||||
|
@ -2965,6 +3211,12 @@ static void intel_setup_outputs(struct drm_device *dev)
|
|||
if (I915_READ(HDMID) & PORT_DETECTED)
|
||||
intel_hdmi_init(dev, HDMID);
|
||||
|
||||
if (I915_READ(PCH_DP_C) & DP_DETECTED)
|
||||
intel_dp_init(dev, PCH_DP_C);
|
||||
|
||||
if (I915_READ(PCH_DP_D) & DP_DETECTED)
|
||||
intel_dp_init(dev, PCH_DP_D);
|
||||
|
||||
} else if (IS_I9XX(dev)) {
|
||||
int found;
|
||||
u32 reg;
|
||||
|
@ -3039,6 +3291,10 @@ static void intel_setup_outputs(struct drm_device *dev)
|
|||
(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);
|
||||
|
@ -3148,6 +3404,9 @@ void intel_modeset_init(struct drm_device *dev)
|
|||
if (IS_I965G(dev)) {
|
||||
dev->mode_config.max_width = 8192;
|
||||
dev->mode_config.max_height = 8192;
|
||||
} else if (IS_I9XX(dev)) {
|
||||
dev->mode_config.max_width = 4096;
|
||||
dev->mode_config.max_height = 4096;
|
||||
} else {
|
||||
dev->mode_config.max_width = 2048;
|
||||
dev->mode_config.max_height = 2048;
|
||||
|
|
|
@ -40,6 +40,8 @@
|
|||
|
||||
#define DP_LINK_CONFIGURATION_SIZE 9
|
||||
|
||||
#define IS_eDP(i) ((i)->type == INTEL_OUTPUT_EDP)
|
||||
|
||||
struct intel_dp_priv {
|
||||
uint32_t output_reg;
|
||||
uint32_t DP;
|
||||
|
@ -63,6 +65,19 @@ intel_dp_link_train(struct intel_output *intel_output, uint32_t DP,
|
|||
static void
|
||||
intel_dp_link_down(struct intel_output *intel_output, uint32_t DP);
|
||||
|
||||
void
|
||||
intel_edp_link_config (struct intel_output *intel_output,
|
||||
int *lane_num, int *link_bw)
|
||||
{
|
||||
struct intel_dp_priv *dp_priv = intel_output->dev_priv;
|
||||
|
||||
*lane_num = dp_priv->lane_count;
|
||||
if (dp_priv->link_bw == DP_LINK_BW_1_62)
|
||||
*link_bw = 162000;
|
||||
else if (dp_priv->link_bw == DP_LINK_BW_2_7)
|
||||
*link_bw = 270000;
|
||||
}
|
||||
|
||||
static int
|
||||
intel_dp_max_lane_count(struct intel_output *intel_output)
|
||||
{
|
||||
|
@ -206,7 +221,13 @@ intel_dp_aux_ch(struct intel_output *intel_output,
|
|||
* and would like to run at 2MHz. So, take the
|
||||
* hrawclk value and divide by 2 and use that
|
||||
*/
|
||||
if (IS_eDP(intel_output))
|
||||
aux_clock_divider = 225; /* eDP input clock at 450Mhz */
|
||||
else if (IS_IGDNG(dev))
|
||||
aux_clock_divider = 62; /* IGDNG: input clock fixed at 125Mhz */
|
||||
else
|
||||
aux_clock_divider = intel_hrawclk(dev) / 2;
|
||||
|
||||
/* Must try at least 3 times according to DP spec */
|
||||
for (try = 0; try < 5; try++) {
|
||||
/* Load the send data into the aux channel data registers */
|
||||
|
@ -236,7 +257,7 @@ intel_dp_aux_ch(struct intel_output *intel_output,
|
|||
}
|
||||
|
||||
/* Clear done status and any errors */
|
||||
I915_WRITE(ch_ctl, (ctl |
|
||||
I915_WRITE(ch_ctl, (status |
|
||||
DP_AUX_CH_CTL_DONE |
|
||||
DP_AUX_CH_CTL_TIME_OUT_ERROR |
|
||||
DP_AUX_CH_CTL_RECEIVE_ERROR));
|
||||
|
@ -295,7 +316,7 @@ intel_dp_aux_native_write(struct intel_output *intel_output,
|
|||
return -1;
|
||||
msg[0] = AUX_NATIVE_WRITE << 4;
|
||||
msg[1] = address >> 8;
|
||||
msg[2] = address;
|
||||
msg[2] = address & 0xff;
|
||||
msg[3] = send_bytes - 1;
|
||||
memcpy(&msg[4], send, send_bytes);
|
||||
msg_bytes = send_bytes + 4;
|
||||
|
@ -387,8 +408,8 @@ intel_dp_i2c_init(struct intel_output *intel_output, const char *name)
|
|||
memset(&dp_priv->adapter, '\0', sizeof (dp_priv->adapter));
|
||||
dp_priv->adapter.owner = THIS_MODULE;
|
||||
dp_priv->adapter.class = I2C_CLASS_DDC;
|
||||
strncpy (dp_priv->adapter.name, name, sizeof dp_priv->adapter.name - 1);
|
||||
dp_priv->adapter.name[sizeof dp_priv->adapter.name - 1] = '\0';
|
||||
strncpy (dp_priv->adapter.name, name, sizeof(dp_priv->adapter.name) - 1);
|
||||
dp_priv->adapter.name[sizeof(dp_priv->adapter.name) - 1] = '\0';
|
||||
dp_priv->adapter.algo_data = &dp_priv->algo;
|
||||
dp_priv->adapter.dev.parent = &intel_output->base.kdev;
|
||||
|
||||
|
@ -493,6 +514,23 @@ intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode,
|
|||
intel_dp_compute_m_n(3, lane_count,
|
||||
mode->clock, adjusted_mode->clock, &m_n);
|
||||
|
||||
if (IS_IGDNG(dev)) {
|
||||
if (intel_crtc->pipe == 0) {
|
||||
I915_WRITE(TRANSA_DATA_M1,
|
||||
((m_n.tu - 1) << PIPE_GMCH_DATA_M_TU_SIZE_SHIFT) |
|
||||
m_n.gmch_m);
|
||||
I915_WRITE(TRANSA_DATA_N1, m_n.gmch_n);
|
||||
I915_WRITE(TRANSA_DP_LINK_M1, m_n.link_m);
|
||||
I915_WRITE(TRANSA_DP_LINK_N1, m_n.link_n);
|
||||
} else {
|
||||
I915_WRITE(TRANSB_DATA_M1,
|
||||
((m_n.tu - 1) << PIPE_GMCH_DATA_M_TU_SIZE_SHIFT) |
|
||||
m_n.gmch_m);
|
||||
I915_WRITE(TRANSB_DATA_N1, m_n.gmch_n);
|
||||
I915_WRITE(TRANSB_DP_LINK_M1, m_n.link_m);
|
||||
I915_WRITE(TRANSB_DP_LINK_N1, m_n.link_n);
|
||||
}
|
||||
} else {
|
||||
if (intel_crtc->pipe == 0) {
|
||||
I915_WRITE(PIPEA_GMCH_DATA_M,
|
||||
((m_n.tu - 1) << PIPE_GMCH_DATA_M_TU_SIZE_SHIFT) |
|
||||
|
@ -511,6 +549,7 @@ intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode,
|
|||
I915_WRITE(PIPEB_DP_LINK_N, m_n.link_n);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
|
||||
|
@ -556,8 +595,38 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
|
|||
|
||||
if (intel_crtc->pipe == 1)
|
||||
dp_priv->DP |= DP_PIPEB_SELECT;
|
||||
|
||||
if (IS_eDP(intel_output)) {
|
||||
/* don't miss out required setting for eDP */
|
||||
dp_priv->DP |= DP_PLL_ENABLE;
|
||||
if (adjusted_mode->clock < 200000)
|
||||
dp_priv->DP |= DP_PLL_FREQ_160MHZ;
|
||||
else
|
||||
dp_priv->DP |= DP_PLL_FREQ_270MHZ;
|
||||
}
|
||||
}
|
||||
|
||||
static void igdng_edp_backlight_on (struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
u32 pp;
|
||||
|
||||
DRM_DEBUG("\n");
|
||||
pp = I915_READ(PCH_PP_CONTROL);
|
||||
pp |= EDP_BLC_ENABLE;
|
||||
I915_WRITE(PCH_PP_CONTROL, pp);
|
||||
}
|
||||
|
||||
static void igdng_edp_backlight_off (struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
u32 pp;
|
||||
|
||||
DRM_DEBUG("\n");
|
||||
pp = I915_READ(PCH_PP_CONTROL);
|
||||
pp &= ~EDP_BLC_ENABLE;
|
||||
I915_WRITE(PCH_PP_CONTROL, pp);
|
||||
}
|
||||
|
||||
static void
|
||||
intel_dp_dpms(struct drm_encoder *encoder, int mode)
|
||||
|
@ -569,11 +638,17 @@ intel_dp_dpms(struct drm_encoder *encoder, int mode)
|
|||
uint32_t dp_reg = I915_READ(dp_priv->output_reg);
|
||||
|
||||
if (mode != DRM_MODE_DPMS_ON) {
|
||||
if (dp_reg & DP_PORT_EN)
|
||||
if (dp_reg & DP_PORT_EN) {
|
||||
intel_dp_link_down(intel_output, dp_priv->DP);
|
||||
if (IS_eDP(intel_output))
|
||||
igdng_edp_backlight_off(dev);
|
||||
}
|
||||
} else {
|
||||
if (!(dp_reg & DP_PORT_EN))
|
||||
if (!(dp_reg & DP_PORT_EN)) {
|
||||
intel_dp_link_train(intel_output, dp_priv->DP, dp_priv->link_configuration);
|
||||
if (IS_eDP(intel_output))
|
||||
igdng_edp_backlight_on(dev);
|
||||
}
|
||||
}
|
||||
dp_priv->dpms_mode = mode;
|
||||
}
|
||||
|
@ -935,6 +1010,23 @@ intel_dp_link_down(struct intel_output *intel_output, uint32_t DP)
|
|||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct intel_dp_priv *dp_priv = intel_output->dev_priv;
|
||||
|
||||
DRM_DEBUG("\n");
|
||||
|
||||
if (IS_eDP(intel_output)) {
|
||||
DP &= ~DP_PLL_ENABLE;
|
||||
I915_WRITE(dp_priv->output_reg, DP);
|
||||
POSTING_READ(dp_priv->output_reg);
|
||||
udelay(100);
|
||||
}
|
||||
|
||||
DP &= ~DP_LINK_TRAIN_MASK;
|
||||
I915_WRITE(dp_priv->output_reg, DP | DP_LINK_TRAIN_PAT_IDLE);
|
||||
POSTING_READ(dp_priv->output_reg);
|
||||
|
||||
udelay(17000);
|
||||
|
||||
if (IS_eDP(intel_output))
|
||||
DP |= DP_LINK_TRAIN_OFF;
|
||||
I915_WRITE(dp_priv->output_reg, DP & ~DP_PORT_EN);
|
||||
POSTING_READ(dp_priv->output_reg);
|
||||
}
|
||||
|
@ -978,6 +1070,24 @@ intel_dp_check_link_status(struct intel_output *intel_output)
|
|||
intel_dp_link_train(intel_output, dp_priv->DP, dp_priv->link_configuration);
|
||||
}
|
||||
|
||||
static enum drm_connector_status
|
||||
igdng_dp_detect(struct drm_connector *connector)
|
||||
{
|
||||
struct intel_output *intel_output = to_intel_output(connector);
|
||||
struct intel_dp_priv *dp_priv = intel_output->dev_priv;
|
||||
enum drm_connector_status status;
|
||||
|
||||
status = connector_status_disconnected;
|
||||
if (intel_dp_aux_native_read(intel_output,
|
||||
0x000, dp_priv->dpcd,
|
||||
sizeof (dp_priv->dpcd)) == sizeof (dp_priv->dpcd))
|
||||
{
|
||||
if (dp_priv->dpcd[0] != 0)
|
||||
status = connector_status_connected;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses CRT_HOTPLUG_EN and CRT_HOTPLUG_STAT to detect DP connection.
|
||||
*
|
||||
|
@ -996,6 +1106,9 @@ intel_dp_detect(struct drm_connector *connector)
|
|||
|
||||
dp_priv->has_audio = false;
|
||||
|
||||
if (IS_IGDNG(dev))
|
||||
return igdng_dp_detect(connector);
|
||||
|
||||
temp = I915_READ(PORT_HOTPLUG_EN);
|
||||
|
||||
I915_WRITE(PORT_HOTPLUG_EN,
|
||||
|
@ -1039,11 +1152,27 @@ intel_dp_detect(struct drm_connector *connector)
|
|||
static int intel_dp_get_modes(struct drm_connector *connector)
|
||||
{
|
||||
struct intel_output *intel_output = to_intel_output(connector);
|
||||
struct drm_device *dev = intel_output->base.dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
int ret;
|
||||
|
||||
/* We should parse the EDID data and find out if it has an audio sink
|
||||
*/
|
||||
|
||||
return intel_ddc_get_modes(intel_output);
|
||||
ret = intel_ddc_get_modes(intel_output);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* if eDP has no EDID, try to use fixed panel mode from VBT */
|
||||
if (IS_eDP(intel_output)) {
|
||||
if (dev_priv->panel_fixed_mode != NULL) {
|
||||
struct drm_display_mode *mode;
|
||||
mode = drm_mode_duplicate(dev, dev_priv->panel_fixed_mode);
|
||||
drm_mode_probed_add(connector, mode);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -1106,6 +1235,7 @@ intel_dp_init(struct drm_device *dev, int output_reg)
|
|||
struct drm_connector *connector;
|
||||
struct intel_output *intel_output;
|
||||
struct intel_dp_priv *dp_priv;
|
||||
const char *name = NULL;
|
||||
|
||||
intel_output = kcalloc(sizeof(struct intel_output) +
|
||||
sizeof(struct intel_dp_priv), 1, GFP_KERNEL);
|
||||
|
@ -1119,6 +1249,9 @@ intel_dp_init(struct drm_device *dev, int output_reg)
|
|||
DRM_MODE_CONNECTOR_DisplayPort);
|
||||
drm_connector_helper_add(connector, &intel_dp_connector_helper_funcs);
|
||||
|
||||
if (output_reg == DP_A)
|
||||
intel_output->type = INTEL_OUTPUT_EDP;
|
||||
else
|
||||
intel_output->type = INTEL_OUTPUT_DISPLAYPORT;
|
||||
|
||||
connector->interlace_allowed = true;
|
||||
|
@ -1139,12 +1272,41 @@ intel_dp_init(struct drm_device *dev, int output_reg)
|
|||
drm_sysfs_connector_add(connector);
|
||||
|
||||
/* Set up the DDC bus. */
|
||||
intel_dp_i2c_init(intel_output,
|
||||
(output_reg == DP_B) ? "DPDDC-B" :
|
||||
(output_reg == DP_C) ? "DPDDC-C" : "DPDDC-D");
|
||||
switch (output_reg) {
|
||||
case DP_A:
|
||||
name = "DPDDC-A";
|
||||
break;
|
||||
case DP_B:
|
||||
case PCH_DP_B:
|
||||
name = "DPDDC-B";
|
||||
break;
|
||||
case DP_C:
|
||||
case PCH_DP_C:
|
||||
name = "DPDDC-C";
|
||||
break;
|
||||
case DP_D:
|
||||
case PCH_DP_D:
|
||||
name = "DPDDC-D";
|
||||
break;
|
||||
}
|
||||
|
||||
intel_dp_i2c_init(intel_output, name);
|
||||
|
||||
intel_output->ddc_bus = &dp_priv->adapter;
|
||||
intel_output->hot_plug = intel_dp_hot_plug;
|
||||
|
||||
if (output_reg == DP_A) {
|
||||
/* initialize panel mode from VBT if available for eDP */
|
||||
if (dev_priv->lfp_lvds_vbt_mode) {
|
||||
dev_priv->panel_fixed_mode =
|
||||
drm_mode_duplicate(dev, dev_priv->lfp_lvds_vbt_mode);
|
||||
if (dev_priv->panel_fixed_mode) {
|
||||
dev_priv->panel_fixed_mode->type |=
|
||||
DRM_MODE_TYPE_PREFERRED;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* For G4X desktop chip, PEG_BAND_GAP_DATA 3:0 must first be written
|
||||
* 0xd. Failure to do so will result in spurious interrupts being
|
||||
* generated on the port when a cable is not attached.
|
||||
|
|
|
@ -55,6 +55,7 @@
|
|||
#define INTEL_OUTPUT_TVOUT 5
|
||||
#define INTEL_OUTPUT_HDMI 6
|
||||
#define INTEL_OUTPUT_DISPLAYPORT 7
|
||||
#define INTEL_OUTPUT_EDP 8
|
||||
|
||||
#define INTEL_DVO_CHIP_NONE 0
|
||||
#define INTEL_DVO_CHIP_LVDS 1
|
||||
|
@ -121,6 +122,8 @@ extern void intel_dp_init(struct drm_device *dev, int dp_reg);
|
|||
void
|
||||
intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode);
|
||||
extern void intel_edp_link_config (struct intel_output *, int *, int *);
|
||||
|
||||
|
||||
extern void intel_crtc_load_lut(struct drm_crtc *crtc);
|
||||
extern void intel_encoder_prepare (struct drm_encoder *encoder);
|
||||
|
|
|
@ -130,16 +130,17 @@ static bool intel_hdmi_mode_fixup(struct drm_encoder *encoder,
|
|||
}
|
||||
|
||||
static enum drm_connector_status
|
||||
intel_hdmi_edid_detect(struct drm_connector *connector)
|
||||
intel_hdmi_detect(struct drm_connector *connector)
|
||||
{
|
||||
struct intel_output *intel_output = to_intel_output(connector);
|
||||
struct intel_hdmi_priv *hdmi_priv = intel_output->dev_priv;
|
||||
struct edid *edid = NULL;
|
||||
enum drm_connector_status status = connector_status_disconnected;
|
||||
|
||||
hdmi_priv->has_hdmi_sink = false;
|
||||
edid = drm_get_edid(&intel_output->base,
|
||||
intel_output->ddc_bus);
|
||||
hdmi_priv->has_hdmi_sink = false;
|
||||
|
||||
if (edid) {
|
||||
if (edid->input & DRM_EDID_INPUT_DIGITAL) {
|
||||
status = connector_status_connected;
|
||||
|
@ -148,67 +149,10 @@ intel_hdmi_edid_detect(struct drm_connector *connector)
|
|||
intel_output->base.display_info.raw_edid = NULL;
|
||||
kfree(edid);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static enum drm_connector_status
|
||||
igdng_hdmi_detect(struct drm_connector *connector)
|
||||
{
|
||||
struct intel_output *intel_output = to_intel_output(connector);
|
||||
struct intel_hdmi_priv *hdmi_priv = intel_output->dev_priv;
|
||||
|
||||
/* FIXME hotplug detect */
|
||||
|
||||
hdmi_priv->has_hdmi_sink = false;
|
||||
return intel_hdmi_edid_detect(connector);
|
||||
}
|
||||
|
||||
static enum drm_connector_status
|
||||
intel_hdmi_detect(struct drm_connector *connector)
|
||||
{
|
||||
struct drm_device *dev = connector->dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct intel_output *intel_output = to_intel_output(connector);
|
||||
struct intel_hdmi_priv *hdmi_priv = intel_output->dev_priv;
|
||||
u32 temp, bit;
|
||||
|
||||
if (IS_IGDNG(dev))
|
||||
return igdng_hdmi_detect(connector);
|
||||
|
||||
temp = I915_READ(PORT_HOTPLUG_EN);
|
||||
|
||||
switch (hdmi_priv->sdvox_reg) {
|
||||
case SDVOB:
|
||||
temp |= HDMIB_HOTPLUG_INT_EN;
|
||||
break;
|
||||
case SDVOC:
|
||||
temp |= HDMIC_HOTPLUG_INT_EN;
|
||||
break;
|
||||
default:
|
||||
return connector_status_unknown;
|
||||
}
|
||||
|
||||
I915_WRITE(PORT_HOTPLUG_EN, temp);
|
||||
|
||||
POSTING_READ(PORT_HOTPLUG_EN);
|
||||
|
||||
switch (hdmi_priv->sdvox_reg) {
|
||||
case SDVOB:
|
||||
bit = HDMIB_HOTPLUG_INT_STATUS;
|
||||
break;
|
||||
case SDVOC:
|
||||
bit = HDMIC_HOTPLUG_INT_STATUS;
|
||||
break;
|
||||
default:
|
||||
return connector_status_unknown;
|
||||
}
|
||||
|
||||
if ((I915_READ(PORT_HOTPLUG_STAT) & bit) != 0)
|
||||
return intel_hdmi_edid_detect(connector);
|
||||
else
|
||||
return connector_status_disconnected;
|
||||
}
|
||||
|
||||
static int intel_hdmi_get_modes(struct drm_connector *connector)
|
||||
{
|
||||
struct intel_output *intel_output = to_intel_output(connector);
|
||||
|
|
|
@ -778,6 +778,14 @@ static const struct dmi_system_id intel_no_lvds[] = {
|
|||
DMI_MATCH(DMI_PRODUCT_NAME, "i965GMx-IF"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.callback = intel_no_lvds_dmi_callback,
|
||||
.ident = "AOpen Mini PC MP915",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_BOARD_VENDOR, "AOpen"),
|
||||
DMI_MATCH(DMI_BOARD_NAME, "i915GMx-F"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.callback = intel_no_lvds_dmi_callback,
|
||||
.ident = "Aopen i945GTt-VFA",
|
||||
|
@ -884,6 +892,10 @@ void intel_lvds_init(struct drm_device *dev)
|
|||
if (IS_IGDNG(dev)) {
|
||||
if ((I915_READ(PCH_LVDS) & LVDS_DETECTED) == 0)
|
||||
return;
|
||||
if (dev_priv->edp_support) {
|
||||
DRM_DEBUG("disable LVDS for eDP support\n");
|
||||
return;
|
||||
}
|
||||
gpio = PCH_GPIOC;
|
||||
}
|
||||
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include "drm.h"
|
||||
#include "drm_crtc.h"
|
||||
#include "intel_drv.h"
|
||||
#include "drm_edid.h"
|
||||
#include "i915_drm.h"
|
||||
#include "i915_drv.h"
|
||||
#include "intel_sdvo_regs.h"
|
||||
|
@ -55,6 +56,12 @@ struct intel_sdvo_priv {
|
|||
/* Pixel clock limitations reported by the SDVO device, in kHz */
|
||||
int pixel_clock_min, pixel_clock_max;
|
||||
|
||||
/*
|
||||
* For multiple function SDVO device,
|
||||
* this is for current attached outputs.
|
||||
*/
|
||||
uint16_t attached_output;
|
||||
|
||||
/**
|
||||
* This is set if we're going to treat the device as TV-out.
|
||||
*
|
||||
|
@ -114,6 +121,9 @@ struct intel_sdvo_priv {
|
|||
u32 save_SDVOX;
|
||||
};
|
||||
|
||||
static bool
|
||||
intel_sdvo_output_setup(struct intel_output *intel_output, uint16_t flags);
|
||||
|
||||
/**
|
||||
* Writes the SDVOB or SDVOC with the given value, but always writes both
|
||||
* SDVOB and SDVOC to work around apparent hardware issues (according to
|
||||
|
@ -1435,41 +1445,96 @@ void intel_sdvo_set_hotplug(struct drm_connector *connector, int on)
|
|||
intel_sdvo_read_response(intel_output, &response, 2);
|
||||
}
|
||||
|
||||
static void
|
||||
intel_sdvo_hdmi_sink_detect(struct drm_connector *connector)
|
||||
static bool
|
||||
intel_sdvo_multifunc_encoder(struct intel_output *intel_output)
|
||||
{
|
||||
struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
|
||||
int caps = 0;
|
||||
|
||||
if (sdvo_priv->caps.output_flags &
|
||||
(SDVO_OUTPUT_TMDS0 | SDVO_OUTPUT_TMDS1))
|
||||
caps++;
|
||||
if (sdvo_priv->caps.output_flags &
|
||||
(SDVO_OUTPUT_RGB0 | SDVO_OUTPUT_RGB1))
|
||||
caps++;
|
||||
if (sdvo_priv->caps.output_flags &
|
||||
(SDVO_OUTPUT_SVID0 | SDVO_OUTPUT_SVID0))
|
||||
caps++;
|
||||
if (sdvo_priv->caps.output_flags &
|
||||
(SDVO_OUTPUT_CVBS0 | SDVO_OUTPUT_CVBS1))
|
||||
caps++;
|
||||
if (sdvo_priv->caps.output_flags &
|
||||
(SDVO_OUTPUT_YPRPB0 | SDVO_OUTPUT_YPRPB1))
|
||||
caps++;
|
||||
|
||||
if (sdvo_priv->caps.output_flags &
|
||||
(SDVO_OUTPUT_SCART0 | SDVO_OUTPUT_SCART1))
|
||||
caps++;
|
||||
|
||||
if (sdvo_priv->caps.output_flags &
|
||||
(SDVO_OUTPUT_LVDS0 | SDVO_OUTPUT_LVDS1))
|
||||
caps++;
|
||||
|
||||
return (caps > 1);
|
||||
}
|
||||
|
||||
enum drm_connector_status
|
||||
intel_sdvo_hdmi_sink_detect(struct drm_connector *connector, u16 response)
|
||||
{
|
||||
struct intel_output *intel_output = to_intel_output(connector);
|
||||
struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
|
||||
enum drm_connector_status status = connector_status_connected;
|
||||
struct edid *edid = NULL;
|
||||
|
||||
edid = drm_get_edid(&intel_output->base,
|
||||
intel_output->ddc_bus);
|
||||
if (edid != NULL) {
|
||||
sdvo_priv->is_hdmi = drm_detect_hdmi_monitor(edid);
|
||||
/* Don't report the output as connected if it's a DVI-I
|
||||
* connector with a non-digital EDID coming out.
|
||||
*/
|
||||
if (response & (SDVO_OUTPUT_TMDS0 | SDVO_OUTPUT_TMDS1)) {
|
||||
if (edid->input & DRM_EDID_INPUT_DIGITAL)
|
||||
sdvo_priv->is_hdmi =
|
||||
drm_detect_hdmi_monitor(edid);
|
||||
else
|
||||
status = connector_status_disconnected;
|
||||
}
|
||||
|
||||
kfree(edid);
|
||||
intel_output->base.display_info.raw_edid = NULL;
|
||||
}
|
||||
|
||||
} else if (response & (SDVO_OUTPUT_TMDS0 | SDVO_OUTPUT_TMDS1))
|
||||
status = connector_status_disconnected;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static enum drm_connector_status intel_sdvo_detect(struct drm_connector *connector)
|
||||
{
|
||||
u8 response[2];
|
||||
uint16_t response;
|
||||
u8 status;
|
||||
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);
|
||||
status = intel_sdvo_read_response(intel_output, &response, 2);
|
||||
|
||||
DRM_DEBUG("SDVO response %d %d\n", response[0], response[1]);
|
||||
DRM_DEBUG("SDVO response %d %d\n", response & 0xff, response >> 8);
|
||||
|
||||
if (status != SDVO_CMD_STATUS_SUCCESS)
|
||||
return connector_status_unknown;
|
||||
|
||||
if ((response[0] != 0) || (response[1] != 0)) {
|
||||
intel_sdvo_hdmi_sink_detect(connector);
|
||||
return connector_status_connected;
|
||||
} else
|
||||
if (response == 0)
|
||||
return connector_status_disconnected;
|
||||
|
||||
if (intel_sdvo_multifunc_encoder(intel_output) &&
|
||||
sdvo_priv->attached_output != response) {
|
||||
if (sdvo_priv->controlled_output != response &&
|
||||
intel_sdvo_output_setup(intel_output, response) != true)
|
||||
return connector_status_unknown;
|
||||
sdvo_priv->attached_output = response;
|
||||
}
|
||||
return intel_sdvo_hdmi_sink_detect(connector, response);
|
||||
}
|
||||
|
||||
static void intel_sdvo_get_ddc_modes(struct drm_connector *connector)
|
||||
|
@ -1866,16 +1931,101 @@ intel_sdvo_get_slave_addr(struct drm_device *dev, int output_device)
|
|||
return 0x72;
|
||||
}
|
||||
|
||||
static bool
|
||||
intel_sdvo_output_setup(struct intel_output *intel_output, uint16_t flags)
|
||||
{
|
||||
struct drm_connector *connector = &intel_output->base;
|
||||
struct drm_encoder *encoder = &intel_output->enc;
|
||||
struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
|
||||
bool ret = true, registered = false;
|
||||
|
||||
sdvo_priv->is_tv = false;
|
||||
intel_output->needs_tv_clock = false;
|
||||
sdvo_priv->is_lvds = false;
|
||||
|
||||
if (device_is_registered(&connector->kdev)) {
|
||||
drm_sysfs_connector_remove(connector);
|
||||
registered = true;
|
||||
}
|
||||
|
||||
if (flags &
|
||||
(SDVO_OUTPUT_TMDS0 | SDVO_OUTPUT_TMDS1)) {
|
||||
if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_TMDS0)
|
||||
sdvo_priv->controlled_output = SDVO_OUTPUT_TMDS0;
|
||||
else
|
||||
sdvo_priv->controlled_output = SDVO_OUTPUT_TMDS1;
|
||||
|
||||
encoder->encoder_type = DRM_MODE_ENCODER_TMDS;
|
||||
connector->connector_type = DRM_MODE_CONNECTOR_DVID;
|
||||
|
||||
if (intel_sdvo_get_supp_encode(intel_output,
|
||||
&sdvo_priv->encode) &&
|
||||
intel_sdvo_get_digital_encoding_mode(intel_output) &&
|
||||
sdvo_priv->is_hdmi) {
|
||||
/* enable hdmi encoding mode if supported */
|
||||
intel_sdvo_set_encode(intel_output, SDVO_ENCODE_HDMI);
|
||||
intel_sdvo_set_colorimetry(intel_output,
|
||||
SDVO_COLORIMETRY_RGB256);
|
||||
connector->connector_type = DRM_MODE_CONNECTOR_HDMIA;
|
||||
}
|
||||
} else if (flags & SDVO_OUTPUT_SVID0) {
|
||||
|
||||
sdvo_priv->controlled_output = SDVO_OUTPUT_SVID0;
|
||||
encoder->encoder_type = DRM_MODE_ENCODER_TVDAC;
|
||||
connector->connector_type = DRM_MODE_CONNECTOR_SVIDEO;
|
||||
sdvo_priv->is_tv = true;
|
||||
intel_output->needs_tv_clock = true;
|
||||
} 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;
|
||||
} else if (flags & SDVO_OUTPUT_RGB1) {
|
||||
|
||||
sdvo_priv->controlled_output = SDVO_OUTPUT_RGB1;
|
||||
encoder->encoder_type = DRM_MODE_ENCODER_DAC;
|
||||
connector->connector_type = DRM_MODE_CONNECTOR_VGA;
|
||||
} else if (flags & SDVO_OUTPUT_LVDS0) {
|
||||
|
||||
sdvo_priv->controlled_output = SDVO_OUTPUT_LVDS0;
|
||||
encoder->encoder_type = DRM_MODE_ENCODER_LVDS;
|
||||
connector->connector_type = DRM_MODE_CONNECTOR_LVDS;
|
||||
sdvo_priv->is_lvds = true;
|
||||
} 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;
|
||||
} else {
|
||||
|
||||
unsigned char bytes[2];
|
||||
|
||||
sdvo_priv->controlled_output = 0;
|
||||
memcpy(bytes, &sdvo_priv->caps.output_flags, 2);
|
||||
DRM_DEBUG_KMS(I915_SDVO,
|
||||
"%s: Unknown SDVO output type (0x%02x%02x)\n",
|
||||
SDVO_NAME(sdvo_priv),
|
||||
bytes[0], bytes[1]);
|
||||
ret = false;
|
||||
}
|
||||
|
||||
if (ret && registered)
|
||||
ret = drm_sysfs_connector_add(connector) == 0 ? true : false;
|
||||
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
bool intel_sdvo_init(struct drm_device *dev, int output_device)
|
||||
{
|
||||
struct drm_connector *connector;
|
||||
struct intel_output *intel_output;
|
||||
struct intel_sdvo_priv *sdvo_priv;
|
||||
|
||||
int connector_type;
|
||||
u8 ch[0x40];
|
||||
int i;
|
||||
int encoder_type;
|
||||
|
||||
intel_output = kcalloc(sizeof(struct intel_output)+sizeof(struct intel_sdvo_priv), 1, GFP_KERNEL);
|
||||
if (!intel_output) {
|
||||
|
@ -1925,88 +2075,28 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device)
|
|||
intel_output->ddc_bus->algo = &intel_sdvo_i2c_bit_algo;
|
||||
|
||||
/* In defaut case sdvo lvds is false */
|
||||
sdvo_priv->is_lvds = false;
|
||||
intel_sdvo_get_capabilities(intel_output, &sdvo_priv->caps);
|
||||
|
||||
if (sdvo_priv->caps.output_flags &
|
||||
(SDVO_OUTPUT_TMDS0 | SDVO_OUTPUT_TMDS1)) {
|
||||
if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_TMDS0)
|
||||
sdvo_priv->controlled_output = SDVO_OUTPUT_TMDS0;
|
||||
else
|
||||
sdvo_priv->controlled_output = SDVO_OUTPUT_TMDS1;
|
||||
|
||||
encoder_type = DRM_MODE_ENCODER_TMDS;
|
||||
connector_type = DRM_MODE_CONNECTOR_DVID;
|
||||
|
||||
if (intel_sdvo_get_supp_encode(intel_output,
|
||||
&sdvo_priv->encode) &&
|
||||
intel_sdvo_get_digital_encoding_mode(intel_output) &&
|
||||
sdvo_priv->is_hdmi) {
|
||||
/* enable hdmi encoding mode if supported */
|
||||
intel_sdvo_set_encode(intel_output, SDVO_ENCODE_HDMI);
|
||||
intel_sdvo_set_colorimetry(intel_output,
|
||||
SDVO_COLORIMETRY_RGB256);
|
||||
connector_type = DRM_MODE_CONNECTOR_HDMIA;
|
||||
}
|
||||
}
|
||||
else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_SVID0)
|
||||
{
|
||||
sdvo_priv->controlled_output = SDVO_OUTPUT_SVID0;
|
||||
encoder_type = DRM_MODE_ENCODER_TVDAC;
|
||||
connector_type = DRM_MODE_CONNECTOR_SVIDEO;
|
||||
sdvo_priv->is_tv = true;
|
||||
intel_output->needs_tv_clock = true;
|
||||
}
|
||||
else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_RGB0)
|
||||
{
|
||||
sdvo_priv->controlled_output = SDVO_OUTPUT_RGB0;
|
||||
encoder_type = DRM_MODE_ENCODER_DAC;
|
||||
connector_type = DRM_MODE_CONNECTOR_VGA;
|
||||
}
|
||||
else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_RGB1)
|
||||
{
|
||||
sdvo_priv->controlled_output = SDVO_OUTPUT_RGB1;
|
||||
encoder_type = DRM_MODE_ENCODER_DAC;
|
||||
connector_type = DRM_MODE_CONNECTOR_VGA;
|
||||
}
|
||||
else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_LVDS0)
|
||||
{
|
||||
sdvo_priv->controlled_output = SDVO_OUTPUT_LVDS0;
|
||||
encoder_type = DRM_MODE_ENCODER_LVDS;
|
||||
connector_type = DRM_MODE_CONNECTOR_LVDS;
|
||||
sdvo_priv->is_lvds = true;
|
||||
}
|
||||
else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_LVDS1)
|
||||
{
|
||||
sdvo_priv->controlled_output = SDVO_OUTPUT_LVDS1;
|
||||
encoder_type = DRM_MODE_ENCODER_LVDS;
|
||||
connector_type = DRM_MODE_CONNECTOR_LVDS;
|
||||
sdvo_priv->is_lvds = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned char bytes[2];
|
||||
|
||||
sdvo_priv->controlled_output = 0;
|
||||
memcpy (bytes, &sdvo_priv->caps.output_flags, 2);
|
||||
DRM_DEBUG_KMS(I915_SDVO,
|
||||
"%s: Unknown SDVO output type (0x%02x%02x)\n",
|
||||
SDVO_NAME(sdvo_priv),
|
||||
bytes[0], bytes[1]);
|
||||
encoder_type = DRM_MODE_ENCODER_NONE;
|
||||
connector_type = DRM_MODE_CONNECTOR_Unknown;
|
||||
if (intel_sdvo_output_setup(intel_output,
|
||||
sdvo_priv->caps.output_flags) != true) {
|
||||
DRM_DEBUG("SDVO output failed to setup on SDVO%c\n",
|
||||
output_device == SDVOB ? 'B' : 'C');
|
||||
goto err_i2c;
|
||||
}
|
||||
|
||||
|
||||
connector = &intel_output->base;
|
||||
drm_connector_init(dev, connector, &intel_sdvo_connector_funcs,
|
||||
connector_type);
|
||||
connector->connector_type);
|
||||
|
||||
drm_connector_helper_add(connector, &intel_sdvo_connector_helper_funcs);
|
||||
connector->interlace_allowed = 0;
|
||||
connector->doublescan_allowed = 0;
|
||||
connector->display_info.subpixel_order = SubPixelHorizontalRGB;
|
||||
|
||||
drm_encoder_init(dev, &intel_output->enc, &intel_sdvo_enc_funcs, encoder_type);
|
||||
drm_encoder_init(dev, &intel_output->enc,
|
||||
&intel_sdvo_enc_funcs, intel_output->enc.encoder_type);
|
||||
|
||||
drm_encoder_helper_add(&intel_output->enc, &intel_sdvo_helper_funcs);
|
||||
|
||||
drm_mode_connector_attach_encoder(&intel_output->base, &intel_output->enc);
|
||||
|
|
|
@ -1490,6 +1490,27 @@ static struct input_res {
|
|||
{"1920x1080", 1920, 1080},
|
||||
};
|
||||
|
||||
/*
|
||||
* Chose preferred mode according to line number of TV format
|
||||
*/
|
||||
static void
|
||||
intel_tv_chose_preferred_modes(struct drm_connector *connector,
|
||||
struct drm_display_mode *mode_ptr)
|
||||
{
|
||||
struct intel_output *intel_output = to_intel_output(connector);
|
||||
const struct tv_mode *tv_mode = intel_tv_mode_find(intel_output);
|
||||
|
||||
if (tv_mode->nbr_end < 480 && mode_ptr->vdisplay == 480)
|
||||
mode_ptr->type |= DRM_MODE_TYPE_PREFERRED;
|
||||
else if (tv_mode->nbr_end > 480) {
|
||||
if (tv_mode->progressive == true && tv_mode->nbr_end < 720) {
|
||||
if (mode_ptr->vdisplay == 720)
|
||||
mode_ptr->type |= DRM_MODE_TYPE_PREFERRED;
|
||||
} else if (mode_ptr->vdisplay == 1080)
|
||||
mode_ptr->type |= DRM_MODE_TYPE_PREFERRED;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stub get_modes function.
|
||||
*
|
||||
|
@ -1544,6 +1565,7 @@ intel_tv_get_modes(struct drm_connector *connector)
|
|||
mode_ptr->clock = (int) tmp;
|
||||
|
||||
mode_ptr->type = DRM_MODE_TYPE_DRIVER;
|
||||
intel_tv_chose_preferred_modes(connector, mode_ptr);
|
||||
drm_mode_probed_add(connector, mode_ptr);
|
||||
count++;
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче