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:
commit
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,12 +354,137 @@ 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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_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");
|
||||
printk(KERN_ERR " PGTBL_ER: 0x%08x\n",
|
||||
pgtbl_err);
|
||||
I915_WRITE(PGTBL_ER, pgtbl_err);
|
||||
(void)I915_READ(PGTBL_ER);
|
||||
}
|
||||
}
|
||||
|
||||
if (eir & I915_ERROR_MEMORY_REFRESH) {
|
||||
printk(KERN_ERR "memory refresh error\n");
|
||||
printk(KERN_ERR "PIPEASTAT: 0x%08x\n",
|
||||
pipea_stats);
|
||||
printk(KERN_ERR "PIPEBSTAT: 0x%08x\n",
|
||||
pipeb_stats);
|
||||
/* pipestat has already been acked */
|
||||
}
|
||||
if (eir & I915_ERROR_INSTRUCTION) {
|
||||
printk(KERN_ERR "instruction error\n");
|
||||
printk(KERN_ERR " INSTPM: 0x%08x\n",
|
||||
I915_READ(INSTPM));
|
||||
if (!IS_I965G(dev)) {
|
||||
u32 ipeir = I915_READ(IPEIR);
|
||||
|
||||
printk(KERN_ERR " IPEIR: 0x%08x\n",
|
||||
I915_READ(IPEIR));
|
||||
printk(KERN_ERR " IPEHR: 0x%08x\n",
|
||||
I915_READ(IPEHR));
|
||||
printk(KERN_ERR " INSTDONE: 0x%08x\n",
|
||||
I915_READ(INSTDONE));
|
||||
printk(KERN_ERR " ACTHD: 0x%08x\n",
|
||||
I915_READ(ACTHD));
|
||||
I915_WRITE(IPEIR, ipeir);
|
||||
(void)I915_READ(IPEIR);
|
||||
} else {
|
||||
u32 ipeir = I915_READ(IPEIR_I965);
|
||||
|
||||
printk(KERN_ERR " IPEIR: 0x%08x\n",
|
||||
I915_READ(IPEIR_I965));
|
||||
printk(KERN_ERR " IPEHR: 0x%08x\n",
|
||||
I915_READ(IPEHR_I965));
|
||||
printk(KERN_ERR " INSTDONE: 0x%08x\n",
|
||||
I915_READ(INSTDONE_I965));
|
||||
printk(KERN_ERR " INSTPS: 0x%08x\n",
|
||||
I915_READ(INSTPS));
|
||||
printk(KERN_ERR " INSTDONE1: 0x%08x\n",
|
||||
I915_READ(INSTDONE1));
|
||||
printk(KERN_ERR " ACTHD: 0x%08x\n",
|
||||
I915_READ(ACTHD_I965));
|
||||
I915_WRITE(IPEIR_I965, ipeir);
|
||||
(void)I915_READ(IPEIR_I965);
|
||||
}
|
||||
}
|
||||
|
||||
I915_WRITE(EIR, eir);
|
||||
(void)I915_READ(EIR);
|
||||
eir = I915_READ(EIR);
|
||||
if (eir) {
|
||||
/*
|
||||
* some errors might have become stuck,
|
||||
* mask them.
|
||||
*/
|
||||
DRM_ERROR("EIR stuck: 0x%08x, masking\n", eir);
|
||||
I915_WRITE(EMR, I915_READ(EMR) | eir);
|
||||
I915_WRITE(IIR, I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT);
|
||||
}
|
||||
|
||||
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;
|
||||
|
@ -372,6 +526,9 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
|
|||
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
|
||||
*/
|
||||
|
@ -403,86 +560,13 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
|
|||
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);
|
||||
queue_work(dev_priv->wq,
|
||||
&dev_priv->hotplug_work);
|
||||
|
||||
I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status);
|
||||
I915_READ(PORT_HOTPLUG_STAT);
|
||||
}
|
||||
|
||||
if (iir & I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT) {
|
||||
u32 eir = I915_READ(EIR);
|
||||
|
||||
i915_capture_error_state(dev);
|
||||
|
||||
printk(KERN_ERR "render error detected, EIR: 0x%08x\n",
|
||||
eir);
|
||||
if (eir & I915_ERROR_PAGE_TABLE) {
|
||||
u32 pgtbl_err = I915_READ(PGTBL_ER);
|
||||
printk(KERN_ERR "page table error\n");
|
||||
printk(KERN_ERR " PGTBL_ER: 0x%08x\n",
|
||||
pgtbl_err);
|
||||
I915_WRITE(PGTBL_ER, pgtbl_err);
|
||||
(void)I915_READ(PGTBL_ER);
|
||||
}
|
||||
if (eir & I915_ERROR_MEMORY_REFRESH) {
|
||||
printk(KERN_ERR "memory refresh error\n");
|
||||
printk(KERN_ERR "PIPEASTAT: 0x%08x\n",
|
||||
pipea_stats);
|
||||
printk(KERN_ERR "PIPEBSTAT: 0x%08x\n",
|
||||
pipeb_stats);
|
||||
/* pipestat has already been acked */
|
||||
}
|
||||
if (eir & I915_ERROR_INSTRUCTION) {
|
||||
printk(KERN_ERR "instruction error\n");
|
||||
printk(KERN_ERR " INSTPM: 0x%08x\n",
|
||||
I915_READ(INSTPM));
|
||||
if (!IS_I965G(dev)) {
|
||||
u32 ipeir = I915_READ(IPEIR);
|
||||
|
||||
printk(KERN_ERR " IPEIR: 0x%08x\n",
|
||||
I915_READ(IPEIR));
|
||||
printk(KERN_ERR " IPEHR: 0x%08x\n",
|
||||
I915_READ(IPEHR));
|
||||
printk(KERN_ERR " INSTDONE: 0x%08x\n",
|
||||
I915_READ(INSTDONE));
|
||||
printk(KERN_ERR " ACTHD: 0x%08x\n",
|
||||
I915_READ(ACTHD));
|
||||
I915_WRITE(IPEIR, ipeir);
|
||||
(void)I915_READ(IPEIR);
|
||||
} else {
|
||||
u32 ipeir = I915_READ(IPEIR_I965);
|
||||
|
||||
printk(KERN_ERR " IPEIR: 0x%08x\n",
|
||||
I915_READ(IPEIR_I965));
|
||||
printk(KERN_ERR " IPEHR: 0x%08x\n",
|
||||
I915_READ(IPEHR_I965));
|
||||
printk(KERN_ERR " INSTDONE: 0x%08x\n",
|
||||
I915_READ(INSTDONE_I965));
|
||||
printk(KERN_ERR " INSTPS: 0x%08x\n",
|
||||
I915_READ(INSTPS));
|
||||
printk(KERN_ERR " INSTDONE1: 0x%08x\n",
|
||||
I915_READ(INSTDONE1));
|
||||
printk(KERN_ERR " ACTHD: 0x%08x\n",
|
||||
I915_READ(ACTHD_I965));
|
||||
I915_WRITE(IPEIR_I965, ipeir);
|
||||
(void)I915_READ(IPEIR_I965);
|
||||
}
|
||||
}
|
||||
|
||||
I915_WRITE(EIR, eir);
|
||||
(void)I915_READ(EIR);
|
||||
eir = I915_READ(EIR);
|
||||
if (eir) {
|
||||
/*
|
||||
* some errors might have become stuck,
|
||||
* mask them.
|
||||
*/
|
||||
DRM_ERROR("EIR stuck: 0x%08x, masking\n", eir);
|
||||
I915_WRITE(EMR, I915_READ(EMR) | eir);
|
||||
I915_WRITE(IIR, I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT);
|
||||
}
|
||||
}
|
||||
|
||||
I915_WRITE(IIR, iir);
|
||||
new_iir = I915_READ(IIR); /* Flush posted writes */
|
||||
|
||||
|
@ -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))
|
||||
dvo_timing = (struct lvds_dvo_timing *)
|
||||
((u8 *)&entry->dvo_timing - 8);
|
||||
else
|
||||
dvo_timing = &entry->dvo_timing;
|
||||
/*
|
||||
* 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 *)
|
||||
((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;
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -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
|
||||
*/
|
||||
aux_clock_divider = intel_hrawclk(dev) / 2;
|
||||
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,22 +514,40 @@ 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 (intel_crtc->pipe == 0) {
|
||||
I915_WRITE(PIPEA_GMCH_DATA_M,
|
||||
((m_n.tu - 1) << PIPE_GMCH_DATA_M_TU_SIZE_SHIFT) |
|
||||
m_n.gmch_m);
|
||||
I915_WRITE(PIPEA_GMCH_DATA_N,
|
||||
m_n.gmch_n);
|
||||
I915_WRITE(PIPEA_DP_LINK_M, m_n.link_m);
|
||||
I915_WRITE(PIPEA_DP_LINK_N, m_n.link_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 {
|
||||
I915_WRITE(PIPEB_GMCH_DATA_M,
|
||||
((m_n.tu - 1) << PIPE_GMCH_DATA_M_TU_SIZE_SHIFT) |
|
||||
m_n.gmch_m);
|
||||
I915_WRITE(PIPEB_GMCH_DATA_N,
|
||||
m_n.gmch_n);
|
||||
I915_WRITE(PIPEB_DP_LINK_M, m_n.link_m);
|
||||
I915_WRITE(PIPEB_DP_LINK_N, m_n.link_n);
|
||||
if (intel_crtc->pipe == 0) {
|
||||
I915_WRITE(PIPEA_GMCH_DATA_M,
|
||||
((m_n.tu - 1) << PIPE_GMCH_DATA_M_TU_SIZE_SHIFT) |
|
||||
m_n.gmch_m);
|
||||
I915_WRITE(PIPEA_GMCH_DATA_N,
|
||||
m_n.gmch_n);
|
||||
I915_WRITE(PIPEA_DP_LINK_M, m_n.link_m);
|
||||
I915_WRITE(PIPEA_DP_LINK_N, m_n.link_n);
|
||||
} else {
|
||||
I915_WRITE(PIPEB_GMCH_DATA_M,
|
||||
((m_n.tu - 1) << PIPE_GMCH_DATA_M_TU_SIZE_SHIFT) |
|
||||
m_n.gmch_m);
|
||||
I915_WRITE(PIPEB_GMCH_DATA_N,
|
||||
m_n.gmch_n);
|
||||
I915_WRITE(PIPEB_DP_LINK_M, m_n.link_m);
|
||||
I915_WRITE(PIPEB_DP_LINK_N, m_n.link_n);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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,7 +1249,10 @@ intel_dp_init(struct drm_device *dev, int output_reg)
|
|||
DRM_MODE_CONNECTOR_DisplayPort);
|
||||
drm_connector_helper_add(connector, &intel_dp_connector_helper_funcs);
|
||||
|
||||
intel_output->type = INTEL_OUTPUT_DISPLAYPORT;
|
||||
if (output_reg == DP_A)
|
||||
intel_output->type = INTEL_OUTPUT_EDP;
|
||||
else
|
||||
intel_output->type = INTEL_OUTPUT_DISPLAYPORT;
|
||||
|
||||
connector->interlace_allowed = true;
|
||||
connector->doublescan_allowed = 0;
|
||||
|
@ -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++;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue