forked from Minki/linux
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:
commit
33f724eb9e
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
||||
/*
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
*/
|
||||
|
@ -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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user