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:
  drm/i915: enable 36bit physical address for hardware status page
  drm/i915: fix eDP pipe mask
  drm/i915: fix pixel color depth setting on eDP
  drm/i915: parse eDP panel color depth from VBT block
  drm/i915: disable LVDS downclock by default
  drm/i915: Fix the incorrect cursor A bit definition in DSPFW2 register
  drm/i915: Remove chatty execbuf failure message.
  drm/i915: remove loop in Ironlake interrupt handler
  drm/i915: Don't wait interruptible for possible plane buffer flush
  drm/i915: try another possible DDC bus for the SDVO device with multiple outputs
  drm/i915: Read the response after issuing DDC bus switch command
  drm/i915: Don't use the child device parsed from VBT to setup HDMI/DP
  drm/i915: Fix resume regression on MSI Wind U100 w/o KMS
  drm/i915: Fix Ironlake M/N/P ranges to match the spec
  drm/i915: Use find_pll function to calculate DPLL setting for LVDS downclock
  drm/i915: Add HP nx9020/SamsungSX20S to ACPI LID quirk list
  drm/i915: disable TV hotplug status check

Trivial conflicts in drivers/gpu/drm/i915/i915_drv.c due to i915
non-modeset suspend fix with different comment.
This commit is contained in:
Linus Torvalds 2010-01-16 10:44:38 -08:00
commit 33f724eb9e
15 changed files with 307 additions and 225 deletions

View File

@ -2460,10 +2460,14 @@ static int __devinit agp_intel_probe(struct pci_dev *pdev,
&bridge->mode);
}
if (bridge->driver->mask_memory == intel_i965_mask_memory)
if (bridge->driver->mask_memory == intel_i965_mask_memory) {
if (pci_set_dma_mask(intel_private.pcidev, DMA_BIT_MASK(36)))
dev_err(&intel_private.pcidev->dev,
"set gfx device dma mask 36bit failed!\n");
else
pci_set_consistent_dma_mask(intel_private.pcidev,
DMA_BIT_MASK(36));
}
pci_set_drvdata(pdev, bridge);
return agp_add_bridge(bridge);

View File

@ -134,6 +134,10 @@ static int i915_init_phys_hws(struct drm_device *dev)
memset(dev_priv->hw_status_page, 0, PAGE_SIZE);
if (IS_I965G(dev))
dev_priv->dma_status_page |= (dev_priv->dma_status_page >> 28) &
0xf0;
I915_WRITE(HWS_PGA, dev_priv->dma_status_page);
DRM_DEBUG_DRIVER("Enabled hardware status page\n");
return 0;

View File

@ -45,6 +45,9 @@ module_param_named(fbpercrtc, i915_fbpercrtc, int, 0400);
unsigned int i915_powersave = 1;
module_param_named(powersave, i915_powersave, int, 0400);
unsigned int i915_lvds_downclock = 0;
module_param_named(lvds_downclock, i915_lvds_downclock, int, 0400);
static struct drm_driver driver;
#define INTEL_VGA_DEVICE(id, info) { \
@ -464,8 +467,11 @@ static struct drm_driver driver = {
.lastclose = i915_driver_lastclose,
.preclose = i915_driver_preclose,
.postclose = i915_driver_postclose,
/* Used in place of i915_pm_ops for non-DRIVER_MODESET */
.suspend = i915_suspend,
.resume = i915_resume,
.device_is_agp = i915_driver_device_is_agp,
.enable_vblank = i915_enable_vblank,
.disable_vblank = i915_disable_vblank,

View File

@ -283,6 +283,7 @@ typedef struct drm_i915_private {
unsigned int lvds_use_ssc:1;
unsigned int edp_support:1;
int lvds_ssc_freq;
int edp_bpp;
struct notifier_block lid_notifier;
@ -722,6 +723,7 @@ extern struct drm_ioctl_desc i915_ioctls[];
extern int i915_max_ioctl;
extern unsigned int i915_fbpercrtc;
extern unsigned int i915_powersave;
extern unsigned int i915_lvds_downclock;
extern void i915_save_display(struct drm_device *dev);
extern void i915_restore_display(struct drm_device *dev);
@ -864,6 +866,7 @@ int i915_do_wait_request(struct drm_device *dev, uint32_t seqno, int interruptib
int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf);
int i915_gem_object_set_to_gtt_domain(struct drm_gem_object *obj,
int write);
int i915_gem_object_set_to_display_plane(struct drm_gem_object *obj);
int i915_gem_attach_phys_object(struct drm_device *dev,
struct drm_gem_object *obj, int id);
void i915_gem_detach_phys_object(struct drm_device *dev,

View File

@ -2837,6 +2837,57 @@ i915_gem_object_set_to_gtt_domain(struct drm_gem_object *obj, int write)
return 0;
}
/*
* Prepare buffer for display plane. Use uninterruptible for possible flush
* wait, as in modesetting process we're not supposed to be interrupted.
*/
int
i915_gem_object_set_to_display_plane(struct drm_gem_object *obj)
{
struct drm_device *dev = obj->dev;
struct drm_i915_gem_object *obj_priv = obj->driver_private;
uint32_t old_write_domain, old_read_domains;
int ret;
/* Not valid to be called on unbound objects. */
if (obj_priv->gtt_space == NULL)
return -EINVAL;
i915_gem_object_flush_gpu_write_domain(obj);
/* Wait on any GPU rendering and flushing to occur. */
if (obj_priv->active) {
#if WATCH_BUF
DRM_INFO("%s: object %p wait for seqno %08x\n",
__func__, obj, obj_priv->last_rendering_seqno);
#endif
ret = i915_do_wait_request(dev, obj_priv->last_rendering_seqno, 0);
if (ret != 0)
return ret;
}
old_write_domain = obj->write_domain;
old_read_domains = obj->read_domains;
obj->read_domains &= I915_GEM_DOMAIN_GTT;
i915_gem_object_flush_cpu_write_domain(obj);
/* It should now be out of any other write domains, and we can update
* the domain values for our changes.
*/
BUG_ON((obj->write_domain & ~I915_GEM_DOMAIN_GTT) != 0);
obj->read_domains |= I915_GEM_DOMAIN_GTT;
obj->write_domain = I915_GEM_DOMAIN_GTT;
obj_priv->dirty = 1;
trace_i915_gem_object_change_domain(obj,
old_read_domains,
old_write_domain);
return 0;
}
/**
* Moves a single object to the CPU read, and possibly write domain.
*
@ -4000,8 +4051,6 @@ i915_gem_execbuffer(struct drm_device *dev, void *data,
"back to user (%d)\n",
args->buffer_count, ret);
}
} else {
DRM_ERROR("i915_gem_do_execbuffer returns %d\n", ret);
}
drm_free_large(exec_list);

View File

@ -274,7 +274,6 @@ irqreturn_t ironlake_irq_handler(struct drm_device *dev)
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
int ret = IRQ_NONE;
u32 de_iir, gt_iir, de_ier, pch_iir;
u32 new_de_iir, new_gt_iir, new_pch_iir;
struct drm_i915_master_private *master_priv;
/* disable master interrupt before clearing iir */
@ -286,51 +285,42 @@ irqreturn_t ironlake_irq_handler(struct drm_device *dev)
gt_iir = I915_READ(GTIIR);
pch_iir = I915_READ(SDEIIR);
for (;;) {
if (de_iir == 0 && gt_iir == 0 && pch_iir == 0)
break;
if (de_iir == 0 && gt_iir == 0 && pch_iir == 0)
goto done;
ret = IRQ_HANDLED;
ret = IRQ_HANDLED;
/* should clear PCH hotplug event before clear CPU irq */
I915_WRITE(SDEIIR, pch_iir);
new_pch_iir = I915_READ(SDEIIR);
I915_WRITE(DEIIR, de_iir);
new_de_iir = I915_READ(DEIIR);
I915_WRITE(GTIIR, gt_iir);
new_gt_iir = I915_READ(GTIIR);
if (dev->primary->master) {
master_priv = dev->primary->master->driver_priv;
if (master_priv->sarea_priv)
master_priv->sarea_priv->last_dispatch =
READ_BREADCRUMB(dev_priv);
}
if (gt_iir & GT_USER_INTERRUPT) {
u32 seqno = i915_get_gem_seqno(dev);
dev_priv->mm.irq_gem_seqno = seqno;
trace_i915_gem_request_complete(dev, seqno);
DRM_WAKEUP(&dev_priv->irq_queue);
dev_priv->hangcheck_count = 0;
mod_timer(&dev_priv->hangcheck_timer, jiffies + DRM_I915_HANGCHECK_PERIOD);
}
if (de_iir & DE_GSE)
ironlake_opregion_gse_intr(dev);
/* check event from PCH */
if ((de_iir & DE_PCH_EVENT) &&
(pch_iir & SDE_HOTPLUG_MASK)) {
queue_work(dev_priv->wq, &dev_priv->hotplug_work);
}
de_iir = new_de_iir;
gt_iir = new_gt_iir;
pch_iir = new_pch_iir;
if (dev->primary->master) {
master_priv = dev->primary->master->driver_priv;
if (master_priv->sarea_priv)
master_priv->sarea_priv->last_dispatch =
READ_BREADCRUMB(dev_priv);
}
if (gt_iir & GT_USER_INTERRUPT) {
u32 seqno = i915_get_gem_seqno(dev);
dev_priv->mm.irq_gem_seqno = seqno;
trace_i915_gem_request_complete(dev, seqno);
DRM_WAKEUP(&dev_priv->irq_queue);
dev_priv->hangcheck_count = 0;
mod_timer(&dev_priv->hangcheck_timer, jiffies + DRM_I915_HANGCHECK_PERIOD);
}
if (de_iir & DE_GSE)
ironlake_opregion_gse_intr(dev);
/* check event from PCH */
if ((de_iir & DE_PCH_EVENT) &&
(pch_iir & SDE_HOTPLUG_MASK)) {
queue_work(dev_priv->wq, &dev_priv->hotplug_work);
}
/* should clear PCH hotplug event before clear CPU irq */
I915_WRITE(SDEIIR, pch_iir);
I915_WRITE(GTIIR, gt_iir);
I915_WRITE(DEIIR, de_iir);
done:
I915_WRITE(DEIER, de_ier);
(void)I915_READ(DEIER);

View File

@ -1815,7 +1815,7 @@
#define DSPFW_PLANEB_SHIFT 8
#define DSPFW2 0x70038
#define DSPFW_CURSORA_MASK 0x00003f00
#define DSPFW_CURSORA_SHIFT 16
#define DSPFW_CURSORA_SHIFT 8
#define DSPFW3 0x7003c
#define DSPFW_HPLL_SR_EN (1<<31)
#define DSPFW_CURSOR_SR_SHIFT 24

View File

@ -33,6 +33,8 @@
#define SLAVE_ADDR1 0x70
#define SLAVE_ADDR2 0x72
static int panel_type;
static void *
find_section(struct bdb_header *bdb, int section_id)
{
@ -128,6 +130,7 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv,
dev_priv->lvds_dither = lvds_options->pixel_dither;
if (lvds_options->panel_type == 0xff)
return;
panel_type = lvds_options->panel_type;
lvds_lfp_data = find_section(bdb, BDB_LVDS_LFP_DATA);
if (!lvds_lfp_data)
@ -197,7 +200,8 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv,
memset(temp_mode, 0, sizeof(*temp_mode));
}
kfree(temp_mode);
if (temp_downclock < panel_fixed_mode->clock) {
if (temp_downclock < panel_fixed_mode->clock &&
i915_lvds_downclock) {
dev_priv->lvds_downclock_avail = 1;
dev_priv->lvds_downclock = temp_downclock;
DRM_DEBUG_KMS("LVDS downclock is found in VBT. ",
@ -404,6 +408,34 @@ parse_driver_features(struct drm_i915_private *dev_priv,
dev_priv->render_reclock_avail = true;
}
static void
parse_edp(struct drm_i915_private *dev_priv, struct bdb_header *bdb)
{
struct bdb_edp *edp;
edp = find_section(bdb, BDB_EDP);
if (!edp) {
if (SUPPORTS_EDP(dev_priv->dev) && dev_priv->edp_support) {
DRM_DEBUG_KMS("No eDP BDB found but eDP panel supported,\
assume 18bpp panel color depth.\n");
dev_priv->edp_bpp = 18;
}
return;
}
switch ((edp->color_depth >> (panel_type * 2)) & 3) {
case EDP_18BPP:
dev_priv->edp_bpp = 18;
break;
case EDP_24BPP:
dev_priv->edp_bpp = 24;
break;
case EDP_30BPP:
dev_priv->edp_bpp = 30;
break;
}
}
static void
parse_device_mapping(struct drm_i915_private *dev_priv,
struct bdb_header *bdb)
@ -521,6 +553,7 @@ intel_init_bios(struct drm_device *dev)
parse_sdvo_device_mapping(dev_priv, bdb);
parse_device_mapping(dev_priv, bdb);
parse_driver_features(dev_priv, bdb);
parse_edp(dev_priv, bdb);
pci_unmap_rom(pdev, bios);

View File

@ -98,6 +98,7 @@ struct vbios_data {
#define BDB_SDVO_LVDS_PNP_IDS 24
#define BDB_SDVO_LVDS_POWER_SEQ 25
#define BDB_TV_OPTIONS 26
#define BDB_EDP 27
#define BDB_LVDS_OPTIONS 40
#define BDB_LVDS_LFP_DATA_PTRS 41
#define BDB_LVDS_LFP_DATA 42
@ -426,6 +427,45 @@ struct bdb_driver_features {
u8 custom_vbt_version;
} __attribute__((packed));
#define EDP_18BPP 0
#define EDP_24BPP 1
#define EDP_30BPP 2
#define EDP_RATE_1_62 0
#define EDP_RATE_2_7 1
#define EDP_LANE_1 0
#define EDP_LANE_2 1
#define EDP_LANE_4 3
#define EDP_PREEMPHASIS_NONE 0
#define EDP_PREEMPHASIS_3_5dB 1
#define EDP_PREEMPHASIS_6dB 2
#define EDP_PREEMPHASIS_9_5dB 3
#define EDP_VSWING_0_4V 0
#define EDP_VSWING_0_6V 1
#define EDP_VSWING_0_8V 2
#define EDP_VSWING_1_2V 3
struct edp_power_seq {
u16 t3;
u16 t7;
u16 t9;
u16 t10;
u16 t12;
} __attribute__ ((packed));
struct edp_link_params {
u8 rate:4;
u8 lanes:4;
u8 preemphasis:4;
u8 vswing:4;
} __attribute__ ((packed));
struct bdb_edp {
struct edp_power_seq power_seqs[16];
u32 color_depth;
u32 sdrrs_msa_timing_delay;
struct edp_link_params link_params[16];
} __attribute__ ((packed));
bool intel_init_bios(struct drm_device *dev);
/*

View File

@ -70,8 +70,6 @@ struct intel_limit {
intel_p2_t p2;
bool (* find_pll)(const intel_limit_t *, struct drm_crtc *,
int, int, intel_clock_t *);
bool (* find_reduced_pll)(const intel_limit_t *, struct drm_crtc *,
int, int, intel_clock_t *);
};
#define I8XX_DOT_MIN 25000
@ -243,11 +241,11 @@ struct intel_limit {
#define IRONLAKE_VCO_MIN 1760000
#define IRONLAKE_VCO_MAX 3510000
#define IRONLAKE_N_MIN 1
#define IRONLAKE_N_MAX 5
#define IRONLAKE_N_MAX 6
#define IRONLAKE_M_MIN 79
#define IRONLAKE_M_MAX 118
#define IRONLAKE_M_MAX 127
#define IRONLAKE_M1_MIN 12
#define IRONLAKE_M1_MAX 23
#define IRONLAKE_M1_MAX 22
#define IRONLAKE_M2_MIN 5
#define IRONLAKE_M2_MAX 9
#define IRONLAKE_P_SDVO_DAC_MIN 5
@ -274,9 +272,6 @@ static bool
intel_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
int target, int refclk, intel_clock_t *best_clock);
static bool
intel_find_best_reduced_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
int target, int refclk, intel_clock_t *best_clock);
static bool
intel_g4x_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
int target, int refclk, intel_clock_t *best_clock);
@ -299,7 +294,6 @@ static const intel_limit_t intel_limits_i8xx_dvo = {
.p2 = { .dot_limit = I8XX_P2_SLOW_LIMIT,
.p2_slow = I8XX_P2_SLOW, .p2_fast = I8XX_P2_FAST },
.find_pll = intel_find_best_PLL,
.find_reduced_pll = intel_find_best_reduced_PLL,
};
static const intel_limit_t intel_limits_i8xx_lvds = {
@ -314,7 +308,6 @@ static const intel_limit_t intel_limits_i8xx_lvds = {
.p2 = { .dot_limit = I8XX_P2_SLOW_LIMIT,
.p2_slow = I8XX_P2_LVDS_SLOW, .p2_fast = I8XX_P2_LVDS_FAST },
.find_pll = intel_find_best_PLL,
.find_reduced_pll = intel_find_best_reduced_PLL,
};
static const intel_limit_t intel_limits_i9xx_sdvo = {
@ -329,7 +322,6 @@ static const intel_limit_t intel_limits_i9xx_sdvo = {
.p2 = { .dot_limit = I9XX_P2_SDVO_DAC_SLOW_LIMIT,
.p2_slow = I9XX_P2_SDVO_DAC_SLOW, .p2_fast = I9XX_P2_SDVO_DAC_FAST },
.find_pll = intel_find_best_PLL,
.find_reduced_pll = intel_find_best_reduced_PLL,
};
static const intel_limit_t intel_limits_i9xx_lvds = {
@ -347,7 +339,6 @@ static const intel_limit_t intel_limits_i9xx_lvds = {
.p2 = { .dot_limit = I9XX_P2_LVDS_SLOW_LIMIT,
.p2_slow = I9XX_P2_LVDS_SLOW, .p2_fast = I9XX_P2_LVDS_FAST },
.find_pll = intel_find_best_PLL,
.find_reduced_pll = intel_find_best_reduced_PLL,
};
/* below parameter and function is for G4X Chipset Family*/
@ -365,7 +356,6 @@ static const intel_limit_t intel_limits_g4x_sdvo = {
.p2_fast = G4X_P2_SDVO_FAST
},
.find_pll = intel_g4x_find_best_PLL,
.find_reduced_pll = intel_g4x_find_best_PLL,
};
static const intel_limit_t intel_limits_g4x_hdmi = {
@ -382,7 +372,6 @@ static const intel_limit_t intel_limits_g4x_hdmi = {
.p2_fast = G4X_P2_HDMI_DAC_FAST
},
.find_pll = intel_g4x_find_best_PLL,
.find_reduced_pll = intel_g4x_find_best_PLL,
};
static const intel_limit_t intel_limits_g4x_single_channel_lvds = {
@ -407,7 +396,6 @@ static const intel_limit_t intel_limits_g4x_single_channel_lvds = {
.p2_fast = G4X_P2_SINGLE_CHANNEL_LVDS_FAST
},
.find_pll = intel_g4x_find_best_PLL,
.find_reduced_pll = intel_g4x_find_best_PLL,
};
static const intel_limit_t intel_limits_g4x_dual_channel_lvds = {
@ -432,7 +420,6 @@ static const intel_limit_t intel_limits_g4x_dual_channel_lvds = {
.p2_fast = G4X_P2_DUAL_CHANNEL_LVDS_FAST
},
.find_pll = intel_g4x_find_best_PLL,
.find_reduced_pll = intel_g4x_find_best_PLL,
};
static const intel_limit_t intel_limits_g4x_display_port = {
@ -470,7 +457,6 @@ static const intel_limit_t intel_limits_pineview_sdvo = {
.p2 = { .dot_limit = I9XX_P2_SDVO_DAC_SLOW_LIMIT,
.p2_slow = I9XX_P2_SDVO_DAC_SLOW, .p2_fast = I9XX_P2_SDVO_DAC_FAST },
.find_pll = intel_find_best_PLL,
.find_reduced_pll = intel_find_best_reduced_PLL,
};
static const intel_limit_t intel_limits_pineview_lvds = {
@ -486,7 +472,6 @@ static const intel_limit_t intel_limits_pineview_lvds = {
.p2 = { .dot_limit = I9XX_P2_LVDS_SLOW_LIMIT,
.p2_slow = I9XX_P2_LVDS_SLOW, .p2_fast = I9XX_P2_LVDS_SLOW },
.find_pll = intel_find_best_PLL,
.find_reduced_pll = intel_find_best_reduced_PLL,
};
static const intel_limit_t intel_limits_ironlake_sdvo = {
@ -768,46 +753,6 @@ intel_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
return (err != target);
}
static bool
intel_find_best_reduced_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
int target, int refclk, intel_clock_t *best_clock)
{
struct drm_device *dev = crtc->dev;
intel_clock_t clock;
int err = target;
bool found = false;
memcpy(&clock, best_clock, sizeof(intel_clock_t));
for (clock.m1 = limit->m1.min; clock.m1 <= limit->m1.max; clock.m1++) {
for (clock.m2 = limit->m2.min; clock.m2 <= limit->m2.max; clock.m2++) {
/* m1 is always 0 in Pineview */
if (clock.m2 >= clock.m1 && !IS_PINEVIEW(dev))
break;
for (clock.n = limit->n.min; clock.n <= limit->n.max;
clock.n++) {
int this_err;
intel_clock(dev, refclk, &clock);
if (!intel_PLL_is_valid(crtc, &clock))
continue;
this_err = abs(clock.dot - target);
if (this_err < err) {
*best_clock = clock;
err = this_err;
found = true;
}
}
}
}
return found;
}
static bool
intel_g4x_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
int target, int refclk, intel_clock_t *best_clock)
@ -1262,7 +1207,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
return ret;
}
ret = i915_gem_object_set_to_gtt_domain(obj, 1);
ret = i915_gem_object_set_to_display_plane(obj);
if (ret != 0) {
i915_gem_object_unpin(obj);
mutex_unlock(&dev->struct_mutex);
@ -2910,10 +2855,8 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
return -EINVAL;
}
if (is_lvds && limit->find_reduced_pll &&
dev_priv->lvds_downclock_avail) {
memcpy(&reduced_clock, &clock, sizeof(intel_clock_t));
has_reduced_clock = limit->find_reduced_pll(limit, crtc,
if (is_lvds && dev_priv->lvds_downclock_avail) {
has_reduced_clock = limit->find_pll(limit, crtc,
dev_priv->lvds_downclock,
refclk,
&reduced_clock);
@ -2981,6 +2924,21 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
temp |= PIPE_8BPC;
else
temp |= PIPE_6BPC;
} else if (is_edp) {
switch (dev_priv->edp_bpp/3) {
case 8:
temp |= PIPE_8BPC;
break;
case 10:
temp |= PIPE_10BPC;
break;
case 6:
temp |= PIPE_6BPC;
break;
case 12:
temp |= PIPE_12BPC;
break;
}
} else
temp |= PIPE_8BPC;
I915_WRITE(pipeconf_reg, temp);

View File

@ -125,9 +125,15 @@ intel_dp_link_clock(uint8_t link_bw)
/* I think this is a fiction */
static int
intel_dp_link_required(int pixel_clock)
intel_dp_link_required(struct drm_device *dev,
struct intel_output *intel_output, int pixel_clock)
{
return pixel_clock * 3;
struct drm_i915_private *dev_priv = dev->dev_private;
if (IS_eDP(intel_output))
return (pixel_clock * dev_priv->edp_bpp) / 8;
else
return pixel_clock * 3;
}
static int
@ -138,7 +144,8 @@ intel_dp_mode_valid(struct drm_connector *connector,
int max_link_clock = intel_dp_link_clock(intel_dp_max_link_bw(intel_output));
int max_lanes = intel_dp_max_lane_count(intel_output);
if (intel_dp_link_required(mode->clock) > max_link_clock * max_lanes)
if (intel_dp_link_required(connector->dev, intel_output, mode->clock)
> max_link_clock * max_lanes)
return MODE_CLOCK_HIGH;
if (mode->clock < 10000)
@ -492,7 +499,8 @@ intel_dp_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode,
for (clock = 0; clock <= max_clock; clock++) {
int link_avail = intel_dp_link_clock(bws[clock]) * lane_count;
if (intel_dp_link_required(mode->clock) <= link_avail) {
if (intel_dp_link_required(encoder->dev, intel_output, mode->clock)
<= link_avail) {
dp_priv->link_bw = bws[clock];
dp_priv->lane_count = lane_count;
adjusted_mode->clock = intel_dp_link_clock(dp_priv->link_bw);
@ -1289,53 +1297,7 @@ intel_dp_hot_plug(struct intel_output *intel_output)
if (dp_priv->dpms_mode == DRM_MODE_DPMS_ON)
intel_dp_check_link_status(intel_output);
}
/*
* Enumerate the child dev array parsed from VBT to check whether
* the given DP is present.
* If it is present, return 1.
* If it is not present, return false.
* If no child dev is parsed from VBT, it is assumed that the given
* DP is present.
*/
static int dp_is_present_in_vbt(struct drm_device *dev, int dp_reg)
{
struct drm_i915_private *dev_priv = dev->dev_private;
struct child_device_config *p_child;
int i, dp_port, ret;
if (!dev_priv->child_dev_num)
return 1;
dp_port = 0;
if (dp_reg == DP_B || dp_reg == PCH_DP_B)
dp_port = PORT_IDPB;
else if (dp_reg == DP_C || dp_reg == PCH_DP_C)
dp_port = PORT_IDPC;
else if (dp_reg == DP_D || dp_reg == PCH_DP_D)
dp_port = PORT_IDPD;
ret = 0;
for (i = 0; i < dev_priv->child_dev_num; i++) {
p_child = dev_priv->child_dev + i;
/*
* If the device type is not DP, continue.
*/
if (p_child->device_type != DEVICE_TYPE_DP &&
p_child->device_type != DEVICE_TYPE_eDP)
continue;
/* Find the eDP port */
if (dp_reg == DP_A && p_child->device_type == DEVICE_TYPE_eDP) {
ret = 1;
break;
}
/* Find the DP port */
if (p_child->dvo_port == dp_port) {
ret = 1;
break;
}
}
return ret;
}
void
intel_dp_init(struct drm_device *dev, int output_reg)
{
@ -1345,10 +1307,6 @@ intel_dp_init(struct drm_device *dev, int output_reg)
struct intel_dp_priv *dp_priv;
const char *name = NULL;
if (!dp_is_present_in_vbt(dev, output_reg)) {
DRM_DEBUG_KMS("DP is not present. Ignore it\n");
return;
}
intel_output = kcalloc(sizeof(struct intel_output) +
sizeof(struct intel_dp_priv), 1, GFP_KERNEL);
if (!intel_output)
@ -1373,11 +1331,10 @@ intel_dp_init(struct drm_device *dev, int output_reg)
else if (output_reg == DP_D || output_reg == PCH_DP_D)
intel_output->clone_mask = (1 << INTEL_DP_D_CLONE_BIT);
if (IS_eDP(intel_output)) {
intel_output->crtc_mask = (1 << 1);
if (IS_eDP(intel_output))
intel_output->clone_mask = (1 << INTEL_EDP_CLONE_BIT);
} else
intel_output->crtc_mask = (1 << 0) | (1 << 1);
intel_output->crtc_mask = (1 << 0) | (1 << 1);
connector->interlace_allowed = true;
connector->doublescan_allowed = 0;

View File

@ -225,52 +225,6 @@ static const struct drm_encoder_funcs intel_hdmi_enc_funcs = {
.destroy = intel_hdmi_enc_destroy,
};
/*
* Enumerate the child dev array parsed from VBT to check whether
* the given HDMI is present.
* If it is present, return 1.
* If it is not present, return false.
* If no child dev is parsed from VBT, it assumes that the given
* HDMI is present.
*/
static int hdmi_is_present_in_vbt(struct drm_device *dev, int hdmi_reg)
{
struct drm_i915_private *dev_priv = dev->dev_private;
struct child_device_config *p_child;
int i, hdmi_port, ret;
if (!dev_priv->child_dev_num)
return 1;
if (hdmi_reg == SDVOB)
hdmi_port = DVO_B;
else if (hdmi_reg == SDVOC)
hdmi_port = DVO_C;
else if (hdmi_reg == HDMIB)
hdmi_port = DVO_B;
else if (hdmi_reg == HDMIC)
hdmi_port = DVO_C;
else if (hdmi_reg == HDMID)
hdmi_port = DVO_D;
else
return 0;
ret = 0;
for (i = 0; i < dev_priv->child_dev_num; i++) {
p_child = dev_priv->child_dev + i;
/*
* If the device type is not HDMI, continue.
*/
if (p_child->device_type != DEVICE_TYPE_HDMI)
continue;
/* Find the HDMI port */
if (p_child->dvo_port == hdmi_port) {
ret = 1;
break;
}
}
return ret;
}
void intel_hdmi_init(struct drm_device *dev, int sdvox_reg)
{
struct drm_i915_private *dev_priv = dev->dev_private;
@ -278,10 +232,6 @@ void intel_hdmi_init(struct drm_device *dev, int sdvox_reg)
struct intel_output *intel_output;
struct intel_hdmi_priv *hdmi_priv;
if (!hdmi_is_present_in_vbt(dev, sdvox_reg)) {
DRM_DEBUG_KMS("HDMI is not present. Ignored it \n");
return;
}
intel_output = kcalloc(sizeof(struct intel_output) +
sizeof(struct intel_hdmi_priv), 1, GFP_KERNEL);
if (!intel_output)

View File

@ -601,6 +601,20 @@ static void intel_lvds_mode_set(struct drm_encoder *encoder,
/* Some lid devices report incorrect lid status, assume they're connected */
static const struct dmi_system_id bad_lid_status[] = {
{
.ident = "Compaq nx9020",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
DMI_MATCH(DMI_BOARD_NAME, "3084"),
},
},
{
.ident = "Samsung SX20S",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Phoenix Technologies LTD"),
DMI_MATCH(DMI_BOARD_NAME, "SX20S"),
},
},
{
.ident = "Aspire One",
.matches = {
@ -912,7 +926,8 @@ static void intel_find_lvds_downclock(struct drm_device *dev,
}
}
mutex_unlock(&dev->mode_config.mutex);
if (temp_downclock < panel_fixed_mode->clock) {
if (temp_downclock < panel_fixed_mode->clock &&
i915_lvds_downclock) {
/* We found the downclock for LVDS. */
dev_priv->lvds_downclock_avail = 1;
dev_priv->lvds_downclock = temp_downclock;

View File

@ -462,14 +462,63 @@ static int intel_sdvo_get_pixel_multiplier(struct drm_display_mode *mode)
}
/**
* Don't check status code from this as it switches the bus back to the
* SDVO chips which defeats the purpose of doing a bus switch in the first
* place.
* Try to read the response after issuie the DDC switch command. But it
* is noted that we must do the action of reading response and issuing DDC
* switch command in one I2C transaction. Otherwise when we try to start
* another I2C transaction after issuing the DDC bus switch, it will be
* switched to the internal SDVO register.
*/
static void intel_sdvo_set_control_bus_switch(struct intel_output *intel_output,
u8 target)
{
intel_sdvo_write_cmd(intel_output, SDVO_CMD_SET_CONTROL_BUS_SWITCH, &target, 1);
struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
u8 out_buf[2], cmd_buf[2], ret_value[2], ret;
struct i2c_msg msgs[] = {
{
.addr = sdvo_priv->slave_addr >> 1,
.flags = 0,
.len = 2,
.buf = out_buf,
},
/* the following two are to read the response */
{
.addr = sdvo_priv->slave_addr >> 1,
.flags = 0,
.len = 1,
.buf = cmd_buf,
},
{
.addr = sdvo_priv->slave_addr >> 1,
.flags = I2C_M_RD,
.len = 1,
.buf = ret_value,
},
};
intel_sdvo_debug_write(intel_output, SDVO_CMD_SET_CONTROL_BUS_SWITCH,
&target, 1);
/* write the DDC switch command argument */
intel_sdvo_write_byte(intel_output, SDVO_I2C_ARG_0, target);
out_buf[0] = SDVO_I2C_OPCODE;
out_buf[1] = SDVO_CMD_SET_CONTROL_BUS_SWITCH;
cmd_buf[0] = SDVO_I2C_CMD_STATUS;
cmd_buf[1] = 0;
ret_value[0] = 0;
ret_value[1] = 0;
ret = i2c_transfer(intel_output->i2c_bus, msgs, 3);
if (ret != 3) {
/* failure in I2C transfer */
DRM_DEBUG_KMS("I2c transfer returned %d\n", ret);
return;
}
if (ret_value[0] != SDVO_CMD_STATUS_SUCCESS) {
DRM_DEBUG_KMS("DDC switch command returns response %d\n",
ret_value[0]);
return;
}
return;
}
static bool intel_sdvo_set_target_input(struct intel_output *intel_output, bool target_0, bool target_1)
@ -1579,6 +1628,32 @@ intel_sdvo_hdmi_sink_detect(struct drm_connector *connector, u16 response)
edid = drm_get_edid(&intel_output->base,
intel_output->ddc_bus);
/* This is only applied to SDVO cards with multiple outputs */
if (edid == NULL && intel_sdvo_multifunc_encoder(intel_output)) {
uint8_t saved_ddc, temp_ddc;
saved_ddc = sdvo_priv->ddc_bus;
temp_ddc = sdvo_priv->ddc_bus >> 1;
/*
* Don't use the 1 as the argument of DDC bus switch to get
* the EDID. It is used for SDVO SPD ROM.
*/
while(temp_ddc > 1) {
sdvo_priv->ddc_bus = temp_ddc;
edid = drm_get_edid(&intel_output->base,
intel_output->ddc_bus);
if (edid) {
/*
* When we can get the EDID, maybe it is the
* correct DDC bus. Update it.
*/
sdvo_priv->ddc_bus = temp_ddc;
break;
}
temp_ddc >>= 1;
}
if (edid == NULL)
sdvo_priv->ddc_bus = saved_ddc;
}
/* when there is no edid and no monitor is connected with VGA
* port, try to use the CRT ddc to read the EDID for DVI-connector
*/

View File

@ -1840,8 +1840,6 @@ intel_tv_init(struct drm_device *dev)
drm_connector_attach_property(connector,
dev->mode_config.tv_bottom_margin_property,
tv_priv->margin[TV_MARGIN_BOTTOM]);
dev_priv->hotplug_supported_mask |= TV_HOTPLUG_INT_STATUS;
out:
drm_sysfs_connector_add(connector);
}