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: Improve CRTDDC mapping by using VBT info drm/i915: Fix CPU-spinning hangs related to fence usage by using an LRU. drm/i915: Set crtc/clone mask in different output devices drm/i915: Always use SDVO_B detect bit for SDVO output detection. drm/i915: Fix typo that broke SVID1 in intel_sdvo_multifunc_encoder() drm/i915: Check if BIOS enabled dual-channel LVDS on 8xx, not only on 9xx drm/i915: Set the multiplier for SDVO on G33 platform
This commit is contained in:
Коммит
b5af754405
|
@ -222,6 +222,7 @@ typedef struct drm_i915_private {
|
|||
unsigned int edp_support:1;
|
||||
int lvds_ssc_freq;
|
||||
|
||||
int crt_ddc_bus; /* -1 = unknown, else GPIO to use for CRT DDC */
|
||||
struct drm_i915_fence_reg fence_regs[16]; /* assume 965 */
|
||||
int fence_reg_start; /* 4 if userland hasn't ioctl'd us yet */
|
||||
int num_fence_regs; /* 8 on pre-965, 16 otherwise */
|
||||
|
@ -384,6 +385,9 @@ typedef struct drm_i915_private {
|
|||
*/
|
||||
struct list_head inactive_list;
|
||||
|
||||
/** LRU list of objects with fence regs on them. */
|
||||
struct list_head fence_list;
|
||||
|
||||
/**
|
||||
* List of breadcrumbs associated with GPU requests currently
|
||||
* outstanding.
|
||||
|
@ -451,6 +455,9 @@ struct drm_i915_gem_object {
|
|||
/** This object's place on the active/flushing/inactive lists */
|
||||
struct list_head list;
|
||||
|
||||
/** This object's place on the fenced object LRU */
|
||||
struct list_head fence_list;
|
||||
|
||||
/**
|
||||
* This is set if the object is on the active or flushing lists
|
||||
* (has pending rendering), and is not set if it's on inactive (ready
|
||||
|
|
|
@ -978,6 +978,7 @@ int
|
|||
i915_gem_set_domain_ioctl(struct drm_device *dev, void *data,
|
||||
struct drm_file *file_priv)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct drm_i915_gem_set_domain *args = data;
|
||||
struct drm_gem_object *obj;
|
||||
uint32_t read_domains = args->read_domains;
|
||||
|
@ -1010,8 +1011,18 @@ i915_gem_set_domain_ioctl(struct drm_device *dev, void *data,
|
|||
obj, obj->size, read_domains, write_domain);
|
||||
#endif
|
||||
if (read_domains & I915_GEM_DOMAIN_GTT) {
|
||||
struct drm_i915_gem_object *obj_priv = obj->driver_private;
|
||||
|
||||
ret = i915_gem_object_set_to_gtt_domain(obj, write_domain != 0);
|
||||
|
||||
/* Update the LRU on the fence for the CPU access that's
|
||||
* about to occur.
|
||||
*/
|
||||
if (obj_priv->fence_reg != I915_FENCE_REG_NONE) {
|
||||
list_move_tail(&obj_priv->fence_list,
|
||||
&dev_priv->mm.fence_list);
|
||||
}
|
||||
|
||||
/* Silently promote "you're not bound, there was nothing to do"
|
||||
* to success, since the client was just asking us to
|
||||
* make sure everything was done.
|
||||
|
@ -1155,8 +1166,7 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
|
|||
}
|
||||
|
||||
/* Need a new fence register? */
|
||||
if (obj_priv->fence_reg == I915_FENCE_REG_NONE &&
|
||||
obj_priv->tiling_mode != I915_TILING_NONE) {
|
||||
if (obj_priv->tiling_mode != I915_TILING_NONE) {
|
||||
ret = i915_gem_object_get_fence_reg(obj);
|
||||
if (ret) {
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
|
@ -2208,6 +2218,12 @@ i915_gem_object_get_fence_reg(struct drm_gem_object *obj)
|
|||
struct drm_i915_gem_object *old_obj_priv = NULL;
|
||||
int i, ret, avail;
|
||||
|
||||
/* Just update our place in the LRU if our fence is getting used. */
|
||||
if (obj_priv->fence_reg != I915_FENCE_REG_NONE) {
|
||||
list_move_tail(&obj_priv->fence_list, &dev_priv->mm.fence_list);
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (obj_priv->tiling_mode) {
|
||||
case I915_TILING_NONE:
|
||||
WARN(1, "allocating a fence for non-tiled object?\n");
|
||||
|
@ -2229,7 +2245,6 @@ i915_gem_object_get_fence_reg(struct drm_gem_object *obj)
|
|||
}
|
||||
|
||||
/* First try to find a free reg */
|
||||
try_again:
|
||||
avail = 0;
|
||||
for (i = dev_priv->fence_reg_start; i < dev_priv->num_fence_regs; i++) {
|
||||
reg = &dev_priv->fence_regs[i];
|
||||
|
@ -2243,52 +2258,41 @@ try_again:
|
|||
|
||||
/* None available, try to steal one or wait for a user to finish */
|
||||
if (i == dev_priv->num_fence_regs) {
|
||||
uint32_t seqno = dev_priv->mm.next_gem_seqno;
|
||||
struct drm_gem_object *old_obj = NULL;
|
||||
|
||||
if (avail == 0)
|
||||
return -ENOSPC;
|
||||
|
||||
for (i = dev_priv->fence_reg_start;
|
||||
i < dev_priv->num_fence_regs; i++) {
|
||||
uint32_t this_seqno;
|
||||
list_for_each_entry(old_obj_priv, &dev_priv->mm.fence_list,
|
||||
fence_list) {
|
||||
old_obj = old_obj_priv->obj;
|
||||
|
||||
reg = &dev_priv->fence_regs[i];
|
||||
old_obj_priv = reg->obj->driver_private;
|
||||
reg = &dev_priv->fence_regs[old_obj_priv->fence_reg];
|
||||
|
||||
if (old_obj_priv->pin_count)
|
||||
continue;
|
||||
|
||||
/* Take a reference, as otherwise the wait_rendering
|
||||
* below may cause the object to get freed out from
|
||||
* under us.
|
||||
*/
|
||||
drm_gem_object_reference(old_obj);
|
||||
|
||||
/* i915 uses fences for GPU access to tiled buffers */
|
||||
if (IS_I965G(dev) || !old_obj_priv->active)
|
||||
break;
|
||||
|
||||
/* find the seqno of the first available fence */
|
||||
this_seqno = old_obj_priv->last_rendering_seqno;
|
||||
if (this_seqno != 0 &&
|
||||
reg->obj->write_domain == 0 &&
|
||||
i915_seqno_passed(seqno, this_seqno))
|
||||
seqno = this_seqno;
|
||||
}
|
||||
|
||||
/*
|
||||
* Now things get ugly... we have to wait for one of the
|
||||
* objects to finish before trying again.
|
||||
*/
|
||||
if (i == dev_priv->num_fence_regs) {
|
||||
if (seqno == dev_priv->mm.next_gem_seqno) {
|
||||
i915_gem_flush(dev,
|
||||
I915_GEM_GPU_DOMAINS,
|
||||
I915_GEM_GPU_DOMAINS);
|
||||
seqno = i915_add_request(dev, NULL,
|
||||
I915_GEM_GPU_DOMAINS);
|
||||
if (seqno == 0)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ret = i915_wait_request(dev, seqno);
|
||||
if (ret)
|
||||
/* This brings the object to the head of the LRU if it
|
||||
* had been written to. The only way this should
|
||||
* result in us waiting longer than the expected
|
||||
* optimal amount of time is if there was a
|
||||
* fence-using buffer later that was read-only.
|
||||
*/
|
||||
i915_gem_object_flush_gpu_write_domain(old_obj);
|
||||
ret = i915_gem_object_wait_rendering(old_obj);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
goto try_again;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -2296,10 +2300,15 @@ try_again:
|
|||
* for this object next time we need it.
|
||||
*/
|
||||
i915_gem_release_mmap(reg->obj);
|
||||
i = old_obj_priv->fence_reg;
|
||||
old_obj_priv->fence_reg = I915_FENCE_REG_NONE;
|
||||
list_del_init(&old_obj_priv->fence_list);
|
||||
drm_gem_object_unreference(old_obj);
|
||||
}
|
||||
|
||||
obj_priv->fence_reg = i;
|
||||
list_add_tail(&obj_priv->fence_list, &dev_priv->mm.fence_list);
|
||||
|
||||
reg->obj = obj;
|
||||
|
||||
if (IS_I965G(dev))
|
||||
|
@ -2342,6 +2351,7 @@ i915_gem_clear_fence_reg(struct drm_gem_object *obj)
|
|||
|
||||
dev_priv->fence_regs[obj_priv->fence_reg].obj = NULL;
|
||||
obj_priv->fence_reg = I915_FENCE_REG_NONE;
|
||||
list_del_init(&obj_priv->fence_list);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -3595,9 +3605,7 @@ i915_gem_object_pin(struct drm_gem_object *obj, uint32_t alignment)
|
|||
* Pre-965 chips need a fence register set up in order to
|
||||
* properly handle tiled surfaces.
|
||||
*/
|
||||
if (!IS_I965G(dev) &&
|
||||
obj_priv->fence_reg == I915_FENCE_REG_NONE &&
|
||||
obj_priv->tiling_mode != I915_TILING_NONE) {
|
||||
if (!IS_I965G(dev) && obj_priv->tiling_mode != I915_TILING_NONE) {
|
||||
ret = i915_gem_object_get_fence_reg(obj);
|
||||
if (ret != 0) {
|
||||
if (ret != -EBUSY && ret != -ERESTARTSYS)
|
||||
|
@ -3806,6 +3814,7 @@ int i915_gem_init_object(struct drm_gem_object *obj)
|
|||
obj_priv->obj = obj;
|
||||
obj_priv->fence_reg = I915_FENCE_REG_NONE;
|
||||
INIT_LIST_HEAD(&obj_priv->list);
|
||||
INIT_LIST_HEAD(&obj_priv->fence_list);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -4253,6 +4262,7 @@ i915_gem_load(struct drm_device *dev)
|
|||
INIT_LIST_HEAD(&dev_priv->mm.flushing_list);
|
||||
INIT_LIST_HEAD(&dev_priv->mm.inactive_list);
|
||||
INIT_LIST_HEAD(&dev_priv->mm.request_list);
|
||||
INIT_LIST_HEAD(&dev_priv->mm.fence_list);
|
||||
INIT_DELAYED_WORK(&dev_priv->mm.retire_work,
|
||||
i915_gem_retire_work_handler);
|
||||
dev_priv->mm.next_gem_seqno = 1;
|
||||
|
|
|
@ -59,6 +59,16 @@ find_section(struct bdb_header *bdb, int section_id)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static u16
|
||||
get_blocksize(void *p)
|
||||
{
|
||||
u16 *block_ptr, block_size;
|
||||
|
||||
block_ptr = (u16 *)((char *)p - 2);
|
||||
block_size = *block_ptr;
|
||||
return block_size;
|
||||
}
|
||||
|
||||
static void
|
||||
fill_detail_timing_data(struct drm_display_mode *panel_fixed_mode,
|
||||
struct lvds_dvo_timing *dvo_timing)
|
||||
|
@ -214,6 +224,41 @@ parse_general_features(struct drm_i915_private *dev_priv,
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
parse_general_definitions(struct drm_i915_private *dev_priv,
|
||||
struct bdb_header *bdb)
|
||||
{
|
||||
struct bdb_general_definitions *general;
|
||||
const int crt_bus_map_table[] = {
|
||||
GPIOB,
|
||||
GPIOA,
|
||||
GPIOC,
|
||||
GPIOD,
|
||||
GPIOE,
|
||||
GPIOF,
|
||||
};
|
||||
|
||||
/* Set sensible defaults in case we can't find the general block
|
||||
or it is the wrong chipset */
|
||||
dev_priv->crt_ddc_bus = -1;
|
||||
|
||||
general = find_section(bdb, BDB_GENERAL_DEFINITIONS);
|
||||
if (general) {
|
||||
u16 block_size = get_blocksize(general);
|
||||
if (block_size >= sizeof(*general)) {
|
||||
int bus_pin = general->crt_ddc_gmbus_pin;
|
||||
DRM_DEBUG("crt_ddc_bus_pin: %d\n", bus_pin);
|
||||
if ((bus_pin >= 1) && (bus_pin <= 6)) {
|
||||
dev_priv->crt_ddc_bus =
|
||||
crt_bus_map_table[bus_pin-1];
|
||||
}
|
||||
} else {
|
||||
DRM_DEBUG("BDB_GD too small (%d). Invalid.\n",
|
||||
block_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
parse_sdvo_device_mapping(struct drm_i915_private *dev_priv,
|
||||
struct bdb_header *bdb)
|
||||
|
@ -222,7 +267,7 @@ parse_sdvo_device_mapping(struct drm_i915_private *dev_priv,
|
|||
struct bdb_general_definitions *p_defs;
|
||||
struct child_device_config *p_child;
|
||||
int i, child_device_num, count;
|
||||
u16 block_size, *block_ptr;
|
||||
u16 block_size;
|
||||
|
||||
p_defs = find_section(bdb, BDB_GENERAL_DEFINITIONS);
|
||||
if (!p_defs) {
|
||||
|
@ -240,8 +285,7 @@ parse_sdvo_device_mapping(struct drm_i915_private *dev_priv,
|
|||
return;
|
||||
}
|
||||
/* get the block size of general definitions */
|
||||
block_ptr = (u16 *)((char *)p_defs - 2);
|
||||
block_size = *block_ptr;
|
||||
block_size = get_blocksize(p_defs);
|
||||
/* get the number of child device */
|
||||
child_device_num = (block_size - sizeof(*p_defs)) /
|
||||
sizeof(*p_child);
|
||||
|
@ -362,6 +406,7 @@ intel_init_bios(struct drm_device *dev)
|
|||
|
||||
/* Grab useful general definitions */
|
||||
parse_general_features(dev_priv, bdb);
|
||||
parse_general_definitions(dev_priv, bdb);
|
||||
parse_lfp_panel_data(dev_priv, bdb);
|
||||
parse_sdvo_panel_data(dev_priv, bdb);
|
||||
parse_sdvo_device_mapping(dev_priv, bdb);
|
||||
|
|
|
@ -508,6 +508,7 @@ void intel_crt_init(struct drm_device *dev)
|
|||
{
|
||||
struct drm_connector *connector;
|
||||
struct intel_output *intel_output;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
u32 i2c_reg;
|
||||
|
||||
intel_output = kzalloc(sizeof(struct intel_output), GFP_KERNEL);
|
||||
|
@ -527,8 +528,12 @@ void intel_crt_init(struct drm_device *dev)
|
|||
/* Set up the DDC bus. */
|
||||
if (IS_IGDNG(dev))
|
||||
i2c_reg = PCH_GPIOA;
|
||||
else
|
||||
else {
|
||||
i2c_reg = GPIOA;
|
||||
/* Use VBT information for CRT DDC if available */
|
||||
if (dev_priv->crt_ddc_bus != -1)
|
||||
i2c_reg = dev_priv->crt_ddc_bus;
|
||||
}
|
||||
intel_output->ddc_bus = intel_i2c_create(dev, i2c_reg, "CRTDDC_A");
|
||||
if (!intel_output->ddc_bus) {
|
||||
dev_printk(KERN_ERR, &dev->pdev->dev, "DDC bus registration "
|
||||
|
@ -537,6 +542,10 @@ void intel_crt_init(struct drm_device *dev)
|
|||
}
|
||||
|
||||
intel_output->type = INTEL_OUTPUT_ANALOG;
|
||||
intel_output->clone_mask = (1 << INTEL_SDVO_NON_TV_CLONE_BIT) |
|
||||
(1 << INTEL_ANALOG_CLONE_BIT) |
|
||||
(1 << INTEL_SDVO_LVDS_CLONE_BIT);
|
||||
intel_output->crtc_mask = (1 << 0) | (1 << 1);
|
||||
connector->interlace_allowed = 0;
|
||||
connector->doublescan_allowed = 0;
|
||||
|
||||
|
|
|
@ -666,7 +666,7 @@ intel_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
|
|||
intel_clock_t clock;
|
||||
int err = target;
|
||||
|
||||
if (IS_I9XX(dev) && intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) &&
|
||||
if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) &&
|
||||
(I915_READ(LVDS)) != 0) {
|
||||
/*
|
||||
* For LVDS, if the panel is on, just rely on its current
|
||||
|
@ -2396,7 +2396,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
|
|||
if (is_sdvo) {
|
||||
dpll |= DPLL_DVO_HIGH_SPEED;
|
||||
sdvo_pixel_multiply = adjusted_mode->clock / mode->clock;
|
||||
if (IS_I945G(dev) || IS_I945GM(dev))
|
||||
if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev))
|
||||
dpll |= (sdvo_pixel_multiply - 1) << SDVO_MULTIPLIER_SHIFT_HIRES;
|
||||
else if (IS_IGDNG(dev))
|
||||
dpll |= (sdvo_pixel_multiply - 1) << PLL_REF_SDVO_HDMI_MULTIPLIER_SHIFT;
|
||||
|
@ -3170,7 +3170,7 @@ static int intel_connector_clones(struct drm_device *dev, int type_mask)
|
|||
|
||||
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
|
||||
struct intel_output *intel_output = to_intel_output(connector);
|
||||
if (type_mask & (1 << intel_output->type))
|
||||
if (type_mask & intel_output->clone_mask)
|
||||
index_mask |= (1 << entry);
|
||||
entry++;
|
||||
}
|
||||
|
@ -3218,30 +3218,30 @@ static void intel_setup_outputs(struct drm_device *dev)
|
|||
intel_dp_init(dev, PCH_DP_D);
|
||||
|
||||
} else if (IS_I9XX(dev)) {
|
||||
int found;
|
||||
u32 reg;
|
||||
bool found = false;
|
||||
|
||||
if (I915_READ(SDVOB) & SDVO_DETECTED) {
|
||||
found = intel_sdvo_init(dev, SDVOB);
|
||||
if (!found && SUPPORTS_INTEGRATED_HDMI(dev))
|
||||
intel_hdmi_init(dev, SDVOB);
|
||||
|
||||
if (!found && SUPPORTS_INTEGRATED_DP(dev))
|
||||
intel_dp_init(dev, DP_B);
|
||||
}
|
||||
|
||||
/* Before G4X SDVOC doesn't have its own detect register */
|
||||
if (IS_G4X(dev))
|
||||
reg = SDVOC;
|
||||
else
|
||||
reg = SDVOB;
|
||||
|
||||
if (I915_READ(reg) & SDVO_DETECTED) {
|
||||
if (I915_READ(SDVOB) & SDVO_DETECTED)
|
||||
found = intel_sdvo_init(dev, SDVOC);
|
||||
if (!found && SUPPORTS_INTEGRATED_HDMI(dev))
|
||||
|
||||
if (!found && (I915_READ(SDVOC) & SDVO_DETECTED)) {
|
||||
|
||||
if (SUPPORTS_INTEGRATED_HDMI(dev))
|
||||
intel_hdmi_init(dev, SDVOC);
|
||||
if (!found && SUPPORTS_INTEGRATED_DP(dev))
|
||||
if (SUPPORTS_INTEGRATED_DP(dev))
|
||||
intel_dp_init(dev, DP_C);
|
||||
}
|
||||
|
||||
if (SUPPORTS_INTEGRATED_DP(dev) && (I915_READ(DP_D) & DP_DETECTED))
|
||||
intel_dp_init(dev, DP_D);
|
||||
} else
|
||||
|
@ -3253,51 +3253,10 @@ static void intel_setup_outputs(struct drm_device *dev)
|
|||
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
|
||||
struct intel_output *intel_output = to_intel_output(connector);
|
||||
struct drm_encoder *encoder = &intel_output->enc;
|
||||
int crtc_mask = 0, clone_mask = 0;
|
||||
|
||||
/* valid crtcs */
|
||||
switch(intel_output->type) {
|
||||
case INTEL_OUTPUT_HDMI:
|
||||
crtc_mask = ((1 << 0)|
|
||||
(1 << 1));
|
||||
clone_mask = ((1 << INTEL_OUTPUT_HDMI));
|
||||
break;
|
||||
case INTEL_OUTPUT_DVO:
|
||||
case INTEL_OUTPUT_SDVO:
|
||||
crtc_mask = ((1 << 0)|
|
||||
(1 << 1));
|
||||
clone_mask = ((1 << INTEL_OUTPUT_ANALOG) |
|
||||
(1 << INTEL_OUTPUT_DVO) |
|
||||
(1 << INTEL_OUTPUT_SDVO));
|
||||
break;
|
||||
case INTEL_OUTPUT_ANALOG:
|
||||
crtc_mask = ((1 << 0)|
|
||||
(1 << 1));
|
||||
clone_mask = ((1 << INTEL_OUTPUT_ANALOG) |
|
||||
(1 << INTEL_OUTPUT_DVO) |
|
||||
(1 << INTEL_OUTPUT_SDVO));
|
||||
break;
|
||||
case INTEL_OUTPUT_LVDS:
|
||||
crtc_mask = (1 << 1);
|
||||
clone_mask = (1 << INTEL_OUTPUT_LVDS);
|
||||
break;
|
||||
case INTEL_OUTPUT_TVOUT:
|
||||
crtc_mask = ((1 << 0) |
|
||||
(1 << 1));
|
||||
clone_mask = (1 << INTEL_OUTPUT_TVOUT);
|
||||
break;
|
||||
case INTEL_OUTPUT_DISPLAYPORT:
|
||||
crtc_mask = ((1 << 0) |
|
||||
(1 << 1));
|
||||
clone_mask = (1 << INTEL_OUTPUT_DISPLAYPORT);
|
||||
break;
|
||||
case INTEL_OUTPUT_EDP:
|
||||
crtc_mask = (1 << 1);
|
||||
clone_mask = (1 << INTEL_OUTPUT_EDP);
|
||||
break;
|
||||
}
|
||||
encoder->possible_crtcs = crtc_mask;
|
||||
encoder->possible_clones = intel_connector_clones(dev, clone_mask);
|
||||
encoder->possible_crtcs = intel_output->crtc_mask;
|
||||
encoder->possible_clones = intel_connector_clones(dev,
|
||||
intel_output->clone_mask);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1254,6 +1254,18 @@ intel_dp_init(struct drm_device *dev, int output_reg)
|
|||
else
|
||||
intel_output->type = INTEL_OUTPUT_DISPLAYPORT;
|
||||
|
||||
if (output_reg == DP_B)
|
||||
intel_output->clone_mask = (1 << INTEL_DP_B_CLONE_BIT);
|
||||
else if (output_reg == DP_C)
|
||||
intel_output->clone_mask = (1 << INTEL_DP_C_CLONE_BIT);
|
||||
else if (output_reg == DP_D)
|
||||
intel_output->clone_mask = (1 << INTEL_DP_D_CLONE_BIT);
|
||||
|
||||
if (IS_eDP(intel_output)) {
|
||||
intel_output->crtc_mask = (1 << 1);
|
||||
intel_output->clone_mask = (1 << INTEL_OUTPUT_EDP);
|
||||
} else
|
||||
intel_output->crtc_mask = (1 << 0) | (1 << 1);
|
||||
connector->interlace_allowed = true;
|
||||
connector->doublescan_allowed = 0;
|
||||
|
||||
|
|
|
@ -57,6 +57,24 @@
|
|||
#define INTEL_OUTPUT_DISPLAYPORT 7
|
||||
#define INTEL_OUTPUT_EDP 8
|
||||
|
||||
/* Intel Pipe Clone Bit */
|
||||
#define INTEL_HDMIB_CLONE_BIT 1
|
||||
#define INTEL_HDMIC_CLONE_BIT 2
|
||||
#define INTEL_HDMID_CLONE_BIT 3
|
||||
#define INTEL_HDMIE_CLONE_BIT 4
|
||||
#define INTEL_HDMIF_CLONE_BIT 5
|
||||
#define INTEL_SDVO_NON_TV_CLONE_BIT 6
|
||||
#define INTEL_SDVO_TV_CLONE_BIT 7
|
||||
#define INTEL_SDVO_LVDS_CLONE_BIT 8
|
||||
#define INTEL_ANALOG_CLONE_BIT 9
|
||||
#define INTEL_TV_CLONE_BIT 10
|
||||
#define INTEL_DP_B_CLONE_BIT 11
|
||||
#define INTEL_DP_C_CLONE_BIT 12
|
||||
#define INTEL_DP_D_CLONE_BIT 13
|
||||
#define INTEL_LVDS_CLONE_BIT 14
|
||||
#define INTEL_DVO_TMDS_CLONE_BIT 15
|
||||
#define INTEL_DVO_LVDS_CLONE_BIT 16
|
||||
|
||||
#define INTEL_DVO_CHIP_NONE 0
|
||||
#define INTEL_DVO_CHIP_LVDS 1
|
||||
#define INTEL_DVO_CHIP_TMDS 2
|
||||
|
@ -86,6 +104,8 @@ struct intel_output {
|
|||
bool needs_tv_clock;
|
||||
void *dev_priv;
|
||||
void (*hot_plug)(struct intel_output *);
|
||||
int crtc_mask;
|
||||
int clone_mask;
|
||||
};
|
||||
|
||||
struct intel_crtc {
|
||||
|
|
|
@ -435,14 +435,20 @@ void intel_dvo_init(struct drm_device *dev)
|
|||
continue;
|
||||
|
||||
intel_output->type = INTEL_OUTPUT_DVO;
|
||||
intel_output->crtc_mask = (1 << 0) | (1 << 1);
|
||||
switch (dvo->type) {
|
||||
case INTEL_DVO_CHIP_TMDS:
|
||||
intel_output->clone_mask =
|
||||
(1 << INTEL_DVO_TMDS_CLONE_BIT) |
|
||||
(1 << INTEL_ANALOG_CLONE_BIT);
|
||||
drm_connector_init(dev, connector,
|
||||
&intel_dvo_connector_funcs,
|
||||
DRM_MODE_CONNECTOR_DVII);
|
||||
encoder_type = DRM_MODE_ENCODER_TMDS;
|
||||
break;
|
||||
case INTEL_DVO_CHIP_LVDS:
|
||||
intel_output->clone_mask =
|
||||
(1 << INTEL_DVO_LVDS_CLONE_BIT);
|
||||
drm_connector_init(dev, connector,
|
||||
&intel_dvo_connector_funcs,
|
||||
DRM_MODE_CONNECTOR_LVDS);
|
||||
|
|
|
@ -230,22 +230,28 @@ void intel_hdmi_init(struct drm_device *dev, int sdvox_reg)
|
|||
|
||||
connector->interlace_allowed = 0;
|
||||
connector->doublescan_allowed = 0;
|
||||
intel_output->crtc_mask = (1 << 0) | (1 << 1);
|
||||
|
||||
/* Set up the DDC bus. */
|
||||
if (sdvox_reg == SDVOB)
|
||||
if (sdvox_reg == SDVOB) {
|
||||
intel_output->clone_mask = (1 << INTEL_HDMIB_CLONE_BIT);
|
||||
intel_output->ddc_bus = intel_i2c_create(dev, GPIOE, "HDMIB");
|
||||
else if (sdvox_reg == SDVOC)
|
||||
} else if (sdvox_reg == SDVOC) {
|
||||
intel_output->clone_mask = (1 << INTEL_HDMIC_CLONE_BIT);
|
||||
intel_output->ddc_bus = intel_i2c_create(dev, GPIOD, "HDMIC");
|
||||
else if (sdvox_reg == HDMIB)
|
||||
} else if (sdvox_reg == HDMIB) {
|
||||
intel_output->clone_mask = (1 << INTEL_HDMID_CLONE_BIT);
|
||||
intel_output->ddc_bus = intel_i2c_create(dev, PCH_GPIOE,
|
||||
"HDMIB");
|
||||
else if (sdvox_reg == HDMIC)
|
||||
} else if (sdvox_reg == HDMIC) {
|
||||
intel_output->clone_mask = (1 << INTEL_HDMIE_CLONE_BIT);
|
||||
intel_output->ddc_bus = intel_i2c_create(dev, PCH_GPIOD,
|
||||
"HDMIC");
|
||||
else if (sdvox_reg == HDMID)
|
||||
} else if (sdvox_reg == HDMID) {
|
||||
intel_output->clone_mask = (1 << INTEL_HDMIF_CLONE_BIT);
|
||||
intel_output->ddc_bus = intel_i2c_create(dev, PCH_GPIOF,
|
||||
"HDMID");
|
||||
|
||||
}
|
||||
if (!intel_output->ddc_bus)
|
||||
goto err_connector;
|
||||
|
||||
|
|
|
@ -916,6 +916,8 @@ void intel_lvds_init(struct drm_device *dev)
|
|||
drm_mode_connector_attach_encoder(&intel_output->base, &intel_output->enc);
|
||||
intel_output->type = INTEL_OUTPUT_LVDS;
|
||||
|
||||
intel_output->clone_mask = (1 << INTEL_LVDS_CLONE_BIT);
|
||||
intel_output->crtc_mask = (1 << 1);
|
||||
drm_encoder_helper_add(encoder, &intel_lvds_helper_funcs);
|
||||
drm_connector_helper_add(connector, &intel_lvds_connector_helper_funcs);
|
||||
connector->display_info.subpixel_order = SubPixelHorizontalRGB;
|
||||
|
|
|
@ -1458,7 +1458,7 @@ intel_sdvo_multifunc_encoder(struct intel_output *intel_output)
|
|||
(SDVO_OUTPUT_RGB0 | SDVO_OUTPUT_RGB1))
|
||||
caps++;
|
||||
if (sdvo_priv->caps.output_flags &
|
||||
(SDVO_OUTPUT_SVID0 | SDVO_OUTPUT_SVID0))
|
||||
(SDVO_OUTPUT_SVID0 | SDVO_OUTPUT_SVID1))
|
||||
caps++;
|
||||
if (sdvo_priv->caps.output_flags &
|
||||
(SDVO_OUTPUT_CVBS0 | SDVO_OUTPUT_CVBS1))
|
||||
|
@ -1967,6 +1967,9 @@ intel_sdvo_output_setup(struct intel_output *intel_output, uint16_t flags)
|
|||
intel_sdvo_set_colorimetry(intel_output,
|
||||
SDVO_COLORIMETRY_RGB256);
|
||||
connector->connector_type = DRM_MODE_CONNECTOR_HDMIA;
|
||||
intel_output->clone_mask =
|
||||
(1 << INTEL_SDVO_NON_TV_CLONE_BIT) |
|
||||
(1 << INTEL_ANALOG_CLONE_BIT);
|
||||
}
|
||||
} else if (flags & SDVO_OUTPUT_SVID0) {
|
||||
|
||||
|
@ -1975,11 +1978,14 @@ intel_sdvo_output_setup(struct intel_output *intel_output, uint16_t flags)
|
|||
connector->connector_type = DRM_MODE_CONNECTOR_SVIDEO;
|
||||
sdvo_priv->is_tv = true;
|
||||
intel_output->needs_tv_clock = true;
|
||||
intel_output->clone_mask = 1 << INTEL_SDVO_TV_CLONE_BIT;
|
||||
} else if (flags & SDVO_OUTPUT_RGB0) {
|
||||
|
||||
sdvo_priv->controlled_output = SDVO_OUTPUT_RGB0;
|
||||
encoder->encoder_type = DRM_MODE_ENCODER_DAC;
|
||||
connector->connector_type = DRM_MODE_CONNECTOR_VGA;
|
||||
intel_output->clone_mask = (1 << INTEL_SDVO_NON_TV_CLONE_BIT) |
|
||||
(1 << INTEL_ANALOG_CLONE_BIT);
|
||||
} else if (flags & SDVO_OUTPUT_RGB1) {
|
||||
|
||||
sdvo_priv->controlled_output = SDVO_OUTPUT_RGB1;
|
||||
|
@ -1991,12 +1997,16 @@ intel_sdvo_output_setup(struct intel_output *intel_output, uint16_t flags)
|
|||
encoder->encoder_type = DRM_MODE_ENCODER_LVDS;
|
||||
connector->connector_type = DRM_MODE_CONNECTOR_LVDS;
|
||||
sdvo_priv->is_lvds = true;
|
||||
intel_output->clone_mask = (1 << INTEL_ANALOG_CLONE_BIT) |
|
||||
(1 << INTEL_SDVO_LVDS_CLONE_BIT);
|
||||
} else if (flags & SDVO_OUTPUT_LVDS1) {
|
||||
|
||||
sdvo_priv->controlled_output = SDVO_OUTPUT_LVDS1;
|
||||
encoder->encoder_type = DRM_MODE_ENCODER_LVDS;
|
||||
connector->connector_type = DRM_MODE_CONNECTOR_LVDS;
|
||||
sdvo_priv->is_lvds = true;
|
||||
intel_output->clone_mask = (1 << INTEL_ANALOG_CLONE_BIT) |
|
||||
(1 << INTEL_SDVO_LVDS_CLONE_BIT);
|
||||
} else {
|
||||
|
||||
unsigned char bytes[2];
|
||||
|
@ -2009,6 +2019,7 @@ intel_sdvo_output_setup(struct intel_output *intel_output, uint16_t flags)
|
|||
bytes[0], bytes[1]);
|
||||
ret = false;
|
||||
}
|
||||
intel_output->crtc_mask = (1 << 0) | (1 << 1);
|
||||
|
||||
if (ret && registered)
|
||||
ret = drm_sysfs_connector_add(connector) == 0 ? true : false;
|
||||
|
|
|
@ -1718,6 +1718,7 @@ intel_tv_init(struct drm_device *dev)
|
|||
if (!intel_output) {
|
||||
return;
|
||||
}
|
||||
|
||||
connector = &intel_output->base;
|
||||
|
||||
drm_connector_init(dev, connector, &intel_tv_connector_funcs,
|
||||
|
@ -1729,6 +1730,7 @@ intel_tv_init(struct drm_device *dev)
|
|||
drm_mode_connector_attach_encoder(&intel_output->base, &intel_output->enc);
|
||||
tv_priv = (struct intel_tv_priv *)(intel_output + 1);
|
||||
intel_output->type = INTEL_OUTPUT_TVOUT;
|
||||
intel_output->clone_mask = (1 << INTEL_TV_CLONE_BIT);
|
||||
intel_output->enc.possible_crtcs = ((1 << 0) | (1 << 1));
|
||||
intel_output->enc.possible_clones = (1 << INTEL_OUTPUT_TVOUT);
|
||||
intel_output->dev_priv = tv_priv;
|
||||
|
|
Загрузка…
Ссылка в новой задаче