Commit b5af7544 authored by Linus Torvalds's avatar Linus Torvalds

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
parents adda7661 db545019
...@@ -222,6 +222,7 @@ typedef struct drm_i915_private { ...@@ -222,6 +222,7 @@ typedef struct drm_i915_private {
unsigned int edp_support:1; unsigned int edp_support:1;
int lvds_ssc_freq; 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 */ struct drm_i915_fence_reg fence_regs[16]; /* assume 965 */
int fence_reg_start; /* 4 if userland hasn't ioctl'd us yet */ int fence_reg_start; /* 4 if userland hasn't ioctl'd us yet */
int num_fence_regs; /* 8 on pre-965, 16 otherwise */ int num_fence_regs; /* 8 on pre-965, 16 otherwise */
...@@ -384,6 +385,9 @@ typedef struct drm_i915_private { ...@@ -384,6 +385,9 @@ typedef struct drm_i915_private {
*/ */
struct list_head inactive_list; 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 * List of breadcrumbs associated with GPU requests currently
* outstanding. * outstanding.
...@@ -451,6 +455,9 @@ struct drm_i915_gem_object { ...@@ -451,6 +455,9 @@ struct drm_i915_gem_object {
/** This object's place on the active/flushing/inactive lists */ /** This object's place on the active/flushing/inactive lists */
struct list_head list; 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 * 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 * (has pending rendering), and is not set if it's on inactive (ready
......
...@@ -978,6 +978,7 @@ int ...@@ -978,6 +978,7 @@ int
i915_gem_set_domain_ioctl(struct drm_device *dev, void *data, i915_gem_set_domain_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv) struct drm_file *file_priv)
{ {
struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_i915_gem_set_domain *args = data; struct drm_i915_gem_set_domain *args = data;
struct drm_gem_object *obj; struct drm_gem_object *obj;
uint32_t read_domains = args->read_domains; uint32_t read_domains = args->read_domains;
...@@ -1010,8 +1011,18 @@ i915_gem_set_domain_ioctl(struct drm_device *dev, void *data, ...@@ -1010,8 +1011,18 @@ i915_gem_set_domain_ioctl(struct drm_device *dev, void *data,
obj, obj->size, read_domains, write_domain); obj, obj->size, read_domains, write_domain);
#endif #endif
if (read_domains & I915_GEM_DOMAIN_GTT) { 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); 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" /* Silently promote "you're not bound, there was nothing to do"
* to success, since the client was just asking us to * to success, since the client was just asking us to
* make sure everything was done. * make sure everything was done.
...@@ -1155,8 +1166,7 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) ...@@ -1155,8 +1166,7 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
} }
/* Need a new fence register? */ /* Need a new fence register? */
if (obj_priv->fence_reg == I915_FENCE_REG_NONE && if (obj_priv->tiling_mode != I915_TILING_NONE) {
obj_priv->tiling_mode != I915_TILING_NONE) {
ret = i915_gem_object_get_fence_reg(obj); ret = i915_gem_object_get_fence_reg(obj);
if (ret) { if (ret) {
mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->struct_mutex);
...@@ -2208,6 +2218,12 @@ i915_gem_object_get_fence_reg(struct drm_gem_object *obj) ...@@ -2208,6 +2218,12 @@ i915_gem_object_get_fence_reg(struct drm_gem_object *obj)
struct drm_i915_gem_object *old_obj_priv = NULL; struct drm_i915_gem_object *old_obj_priv = NULL;
int i, ret, avail; 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) { switch (obj_priv->tiling_mode) {
case I915_TILING_NONE: case I915_TILING_NONE:
WARN(1, "allocating a fence for non-tiled object?\n"); 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) ...@@ -2229,7 +2245,6 @@ i915_gem_object_get_fence_reg(struct drm_gem_object *obj)
} }
/* First try to find a free reg */ /* First try to find a free reg */
try_again:
avail = 0; avail = 0;
for (i = dev_priv->fence_reg_start; i < dev_priv->num_fence_regs; i++) { for (i = dev_priv->fence_reg_start; i < dev_priv->num_fence_regs; i++) {
reg = &dev_priv->fence_regs[i]; reg = &dev_priv->fence_regs[i];
...@@ -2243,52 +2258,41 @@ i915_gem_object_get_fence_reg(struct drm_gem_object *obj) ...@@ -2243,52 +2258,41 @@ i915_gem_object_get_fence_reg(struct drm_gem_object *obj)
/* None available, try to steal one or wait for a user to finish */ /* None available, try to steal one or wait for a user to finish */
if (i == dev_priv->num_fence_regs) { 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) if (avail == 0)
return -ENOSPC; return -ENOSPC;
for (i = dev_priv->fence_reg_start; list_for_each_entry(old_obj_priv, &dev_priv->mm.fence_list,
i < dev_priv->num_fence_regs; i++) { fence_list) {
uint32_t this_seqno; old_obj = old_obj_priv->obj;
reg = &dev_priv->fence_regs[i]; reg = &dev_priv->fence_regs[old_obj_priv->fence_reg];
old_obj_priv = reg->obj->driver_private;
if (old_obj_priv->pin_count) if (old_obj_priv->pin_count)
continue; 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 */ /* i915 uses fences for GPU access to tiled buffers */
if (IS_I965G(dev) || !old_obj_priv->active) if (IS_I965G(dev) || !old_obj_priv->active)
break; break;
/* find the seqno of the first available fence */ /* This brings the object to the head of the LRU if it
this_seqno = old_obj_priv->last_rendering_seqno; * had been written to. The only way this should
if (this_seqno != 0 && * result in us waiting longer than the expected
reg->obj->write_domain == 0 && * optimal amount of time is if there was a
i915_seqno_passed(seqno, this_seqno)) * fence-using buffer later that was read-only.
seqno = this_seqno; */
} i915_gem_object_flush_gpu_write_domain(old_obj);
ret = i915_gem_object_wait_rendering(old_obj);
/* if (ret != 0)
* 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)
return ret; return ret;
goto try_again; break;
} }
/* /*
...@@ -2296,10 +2300,15 @@ i915_gem_object_get_fence_reg(struct drm_gem_object *obj) ...@@ -2296,10 +2300,15 @@ i915_gem_object_get_fence_reg(struct drm_gem_object *obj)
* for this object next time we need it. * for this object next time we need it.
*/ */
i915_gem_release_mmap(reg->obj); i915_gem_release_mmap(reg->obj);
i = old_obj_priv->fence_reg;
old_obj_priv->fence_reg = I915_FENCE_REG_NONE; 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; obj_priv->fence_reg = i;
list_add_tail(&obj_priv->fence_list, &dev_priv->mm.fence_list);
reg->obj = obj; reg->obj = obj;
if (IS_I965G(dev)) if (IS_I965G(dev))
...@@ -2342,6 +2351,7 @@ i915_gem_clear_fence_reg(struct drm_gem_object *obj) ...@@ -2342,6 +2351,7 @@ i915_gem_clear_fence_reg(struct drm_gem_object *obj)
dev_priv->fence_regs[obj_priv->fence_reg].obj = NULL; dev_priv->fence_regs[obj_priv->fence_reg].obj = NULL;
obj_priv->fence_reg = I915_FENCE_REG_NONE; 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) ...@@ -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 * Pre-965 chips need a fence register set up in order to
* properly handle tiled surfaces. * properly handle tiled surfaces.
*/ */
if (!IS_I965G(dev) && if (!IS_I965G(dev) && obj_priv->tiling_mode != I915_TILING_NONE) {
obj_priv->fence_reg == I915_FENCE_REG_NONE &&
obj_priv->tiling_mode != I915_TILING_NONE) {
ret = i915_gem_object_get_fence_reg(obj); ret = i915_gem_object_get_fence_reg(obj);
if (ret != 0) { if (ret != 0) {
if (ret != -EBUSY && ret != -ERESTARTSYS) if (ret != -EBUSY && ret != -ERESTARTSYS)
...@@ -3806,6 +3814,7 @@ int i915_gem_init_object(struct drm_gem_object *obj) ...@@ -3806,6 +3814,7 @@ int i915_gem_init_object(struct drm_gem_object *obj)
obj_priv->obj = obj; obj_priv->obj = obj;
obj_priv->fence_reg = I915_FENCE_REG_NONE; obj_priv->fence_reg = I915_FENCE_REG_NONE;
INIT_LIST_HEAD(&obj_priv->list); INIT_LIST_HEAD(&obj_priv->list);
INIT_LIST_HEAD(&obj_priv->fence_list);
return 0; return 0;
} }
...@@ -4253,6 +4262,7 @@ i915_gem_load(struct drm_device *dev) ...@@ -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.flushing_list);
INIT_LIST_HEAD(&dev_priv->mm.inactive_list); INIT_LIST_HEAD(&dev_priv->mm.inactive_list);
INIT_LIST_HEAD(&dev_priv->mm.request_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, INIT_DELAYED_WORK(&dev_priv->mm.retire_work,
i915_gem_retire_work_handler); i915_gem_retire_work_handler);
dev_priv->mm.next_gem_seqno = 1; dev_priv->mm.next_gem_seqno = 1;
......
...@@ -59,6 +59,16 @@ find_section(struct bdb_header *bdb, int section_id) ...@@ -59,6 +59,16 @@ find_section(struct bdb_header *bdb, int section_id)
return NULL; 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 static void
fill_detail_timing_data(struct drm_display_mode *panel_fixed_mode, fill_detail_timing_data(struct drm_display_mode *panel_fixed_mode,
struct lvds_dvo_timing *dvo_timing) struct lvds_dvo_timing *dvo_timing)
...@@ -214,6 +224,41 @@ parse_general_features(struct drm_i915_private *dev_priv, ...@@ -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 static void
parse_sdvo_device_mapping(struct drm_i915_private *dev_priv, parse_sdvo_device_mapping(struct drm_i915_private *dev_priv,
struct bdb_header *bdb) struct bdb_header *bdb)
...@@ -222,7 +267,7 @@ parse_sdvo_device_mapping(struct drm_i915_private *dev_priv, ...@@ -222,7 +267,7 @@ parse_sdvo_device_mapping(struct drm_i915_private *dev_priv,
struct bdb_general_definitions *p_defs; struct bdb_general_definitions *p_defs;
struct child_device_config *p_child; struct child_device_config *p_child;
int i, child_device_num, count; int i, child_device_num, count;
u16 block_size, *block_ptr; u16 block_size;
p_defs = find_section(bdb, BDB_GENERAL_DEFINITIONS); p_defs = find_section(bdb, BDB_GENERAL_DEFINITIONS);
if (!p_defs) { if (!p_defs) {
...@@ -240,8 +285,7 @@ parse_sdvo_device_mapping(struct drm_i915_private *dev_priv, ...@@ -240,8 +285,7 @@ parse_sdvo_device_mapping(struct drm_i915_private *dev_priv,
return; return;
} }
/* get the block size of general definitions */ /* get the block size of general definitions */
block_ptr = (u16 *)((char *)p_defs - 2); block_size = get_blocksize(p_defs);
block_size = *block_ptr;
/* get the number of child device */ /* get the number of child device */
child_device_num = (block_size - sizeof(*p_defs)) / child_device_num = (block_size - sizeof(*p_defs)) /
sizeof(*p_child); sizeof(*p_child);
...@@ -362,6 +406,7 @@ intel_init_bios(struct drm_device *dev) ...@@ -362,6 +406,7 @@ intel_init_bios(struct drm_device *dev)
/* Grab useful general definitions */ /* Grab useful general definitions */
parse_general_features(dev_priv, bdb); parse_general_features(dev_priv, bdb);
parse_general_definitions(dev_priv, bdb);
parse_lfp_panel_data(dev_priv, bdb); parse_lfp_panel_data(dev_priv, bdb);
parse_sdvo_panel_data(dev_priv, bdb); parse_sdvo_panel_data(dev_priv, bdb);
parse_sdvo_device_mapping(dev_priv, bdb); parse_sdvo_device_mapping(dev_priv, bdb);
......
...@@ -508,6 +508,7 @@ void intel_crt_init(struct drm_device *dev) ...@@ -508,6 +508,7 @@ void intel_crt_init(struct drm_device *dev)
{ {
struct drm_connector *connector; struct drm_connector *connector;
struct intel_output *intel_output; struct intel_output *intel_output;
struct drm_i915_private *dev_priv = dev->dev_private;
u32 i2c_reg; u32 i2c_reg;
intel_output = kzalloc(sizeof(struct intel_output), GFP_KERNEL); intel_output = kzalloc(sizeof(struct intel_output), GFP_KERNEL);
...@@ -527,8 +528,12 @@ void intel_crt_init(struct drm_device *dev) ...@@ -527,8 +528,12 @@ void intel_crt_init(struct drm_device *dev)
/* Set up the DDC bus. */ /* Set up the DDC bus. */
if (IS_IGDNG(dev)) if (IS_IGDNG(dev))
i2c_reg = PCH_GPIOA; i2c_reg = PCH_GPIOA;
else else {
i2c_reg = GPIOA; 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"); intel_output->ddc_bus = intel_i2c_create(dev, i2c_reg, "CRTDDC_A");
if (!intel_output->ddc_bus) { if (!intel_output->ddc_bus) {
dev_printk(KERN_ERR, &dev->pdev->dev, "DDC bus registration " dev_printk(KERN_ERR, &dev->pdev->dev, "DDC bus registration "
...@@ -537,6 +542,10 @@ void intel_crt_init(struct drm_device *dev) ...@@ -537,6 +542,10 @@ void intel_crt_init(struct drm_device *dev)
} }
intel_output->type = INTEL_OUTPUT_ANALOG; 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->interlace_allowed = 0;
connector->doublescan_allowed = 0; connector->doublescan_allowed = 0;
......
...@@ -666,7 +666,7 @@ intel_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc, ...@@ -666,7 +666,7 @@ intel_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
intel_clock_t clock; intel_clock_t clock;
int err = target; 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) { (I915_READ(LVDS)) != 0) {
/* /*
* For LVDS, if the panel is on, just rely on its current * 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, ...@@ -2396,7 +2396,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
if (is_sdvo) { if (is_sdvo) {
dpll |= DPLL_DVO_HIGH_SPEED; dpll |= DPLL_DVO_HIGH_SPEED;
sdvo_pixel_multiply = adjusted_mode->clock / mode->clock; 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; dpll |= (sdvo_pixel_multiply - 1) << SDVO_MULTIPLIER_SHIFT_HIRES;
else if (IS_IGDNG(dev)) else if (IS_IGDNG(dev))
dpll |= (sdvo_pixel_multiply - 1) << PLL_REF_SDVO_HDMI_MULTIPLIER_SHIFT; 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) ...@@ -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) { list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
struct intel_output *intel_output = to_intel_output(connector); 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); index_mask |= (1 << entry);
entry++; entry++;
} }
...@@ -3218,30 +3218,30 @@ static void intel_setup_outputs(struct drm_device *dev) ...@@ -3218,30 +3218,30 @@ static void intel_setup_outputs(struct drm_device *dev)
intel_dp_init(dev, PCH_DP_D); intel_dp_init(dev, PCH_DP_D);
} else if (IS_I9XX(dev)) { } else if (IS_I9XX(dev)) {
int found; bool found = false;
u32 reg;
if (I915_READ(SDVOB) & SDVO_DETECTED) { if (I915_READ(SDVOB) & SDVO_DETECTED) {
found = intel_sdvo_init(dev, SDVOB); found = intel_sdvo_init(dev, SDVOB);
if (!found && SUPPORTS_INTEGRATED_HDMI(dev)) if (!found && SUPPORTS_INTEGRATED_HDMI(dev))
intel_hdmi_init(dev, SDVOB); intel_hdmi_init(dev, SDVOB);
if (!found && SUPPORTS_INTEGRATED_DP(dev)) if (!found && SUPPORTS_INTEGRATED_DP(dev))
intel_dp_init(dev, DP_B); intel_dp_init(dev, DP_B);
} }
/* Before G4X SDVOC doesn't have its own detect register */ /* 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); 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); intel_hdmi_init(dev, SDVOC);
if (!found && SUPPORTS_INTEGRATED_DP(dev)) if (SUPPORTS_INTEGRATED_DP(dev))
intel_dp_init(dev, DP_C); intel_dp_init(dev, DP_C);
} }
if (SUPPORTS_INTEGRATED_DP(dev) && (I915_READ(DP_D) & DP_DETECTED)) if (SUPPORTS_INTEGRATED_DP(dev) && (I915_READ(DP_D) & DP_DETECTED))
intel_dp_init(dev, DP_D); intel_dp_init(dev, DP_D);
} else } else
...@@ -3253,51 +3253,10 @@ static void intel_setup_outputs(struct drm_device *dev) ...@@ -3253,51 +3253,10 @@ static void intel_setup_outputs(struct drm_device *dev)
list_for_each_entry(connector, &dev->mode_config.connector_list, head) { list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
struct intel_output *intel_output = to_intel_output(connector); struct intel_output *intel_output = to_intel_output(connector);
struct drm_encoder *encoder = &intel_output->enc; struct drm_encoder *encoder = &intel_output->enc;
int crtc_mask = 0, clone_mask = 0;
/* valid crtcs */ encoder->possible_crtcs = intel_output->crtc_mask;
switch(intel_output->type) { encoder->possible_clones = intel_connector_clones(dev,
case INTEL_OUTPUT_HDMI: intel_output->clone_mask);
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);
} }
} }
......
...@@ -1254,6 +1254,18 @@ intel_dp_init(struct drm_device *dev, int output_reg) ...@@ -1254,6 +1254,18 @@ intel_dp_init(struct drm_device *dev, int output_reg)
else else
intel_output->type = INTEL_OUTPUT_DISPLAYPORT; 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->interlace_allowed = true;
connector->doublescan_allowed = 0; connector->doublescan_allowed = 0;
......
...@@ -57,6 +57,24 @@ ...@@ -57,6 +57,24 @@
#define INTEL_OUTPUT_DISPLAYPORT 7 #define INTEL_OUTPUT_DISPLAYPORT 7
#define INTEL_OUTPUT_EDP 8 #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_NONE 0
#define INTEL_DVO_CHIP_LVDS 1 #define INTEL_DVO_CHIP_LVDS 1
#define INTEL_DVO_CHIP_TMDS 2 #define INTEL_DVO_CHIP_TMDS 2
...@@ -86,6 +104,8 @@ struct intel_output { ...@@ -86,6 +104,8 @@ struct intel_output {
bool needs_tv_clock; bool needs_tv_clock;
void *dev_priv; void *dev_priv;
void (*hot_plug)(struct intel_output *); void (*hot_plug)(struct intel_output *);
int crtc_mask;
int clone_mask;
}; };
struct intel_crtc { struct intel_crtc {
......
...@@ -435,14 +435,20 @@ void intel_dvo_init(struct drm_device *dev) ...@@ -435,14 +435,20 @@ void intel_dvo_init(struct drm_device *dev)
continue; continue;
intel_output->type = INTEL_OUTPUT_DVO; intel_output->type = INTEL_OUTPUT_DVO;
intel_output->crtc_mask = (1 << 0) | (1 << 1);
switch (dvo->type) { switch (dvo->type) {
case INTEL_DVO_CHIP_TMDS: 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, drm_connector_init(dev, connector,
&intel_dvo_connector_funcs, &intel_dvo_connector_funcs,
DRM_MODE_CONNECTOR_DVII); DRM_MODE_CONNECTOR_DVII);
encoder_type = DRM_MODE_ENCODER_TMDS; encoder_type = DRM_MODE_ENCODER_TMDS;
break; break;
case INTEL_DVO_CHIP_LVDS: case INTEL_DVO_CHIP_LVDS:
intel_output->clone_mask =
(1 << INTEL_DVO_LVDS_CLONE_BIT);
drm_connector_init(dev, connector, drm_connector_init(dev, connector,
&intel_dvo_connector_funcs, &intel_dvo_connector_funcs,
DRM_MODE_CONNECTOR_LVDS); DRM_MODE_CONNECTOR_LVDS);
......
...@@ -230,22 +230,28 @@ void intel_hdmi_init(struct drm_device *dev, int sdvox_reg) ...@@ -230,22 +230,28 @@ void intel_hdmi_init(struct drm_device *dev, int sdvox_reg)
connector->interlace_allowed = 0; connector->interlace_allowed = 0;
connector->doublescan_allowed = 0; connector->doublescan_allowed = 0;
intel_output->crtc_mask = (1 << 0) | (1 << 1);
/* Set up the DDC bus. */ /* 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"); 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"); 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, intel_output->ddc_bus = intel_i2c_create(dev, PCH_GPIOE,
"HDMIB"); "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, intel_output->ddc_bus = intel_i2c_create(dev, PCH_GPIOD,
"HDMIC"); "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, intel_output->ddc_bus = intel_i2c_create(dev, PCH_GPIOF,
"HDMID"); "HDMID");
}
if (!intel_output->ddc_bus) if (!intel_output->ddc_bus)
goto err_connector; goto err_connector;
......
...@@ -916,6 +916,8 @@ void intel_lvds_init(struct drm_device *dev) ...@@ -916,6 +916,8 @@ void intel_lvds_init(struct drm_device *dev)
drm_mode_connector_attach_encoder(&intel_output->base, &intel_output->enc); drm_mode_connector_attach_encoder(&intel_output->base, &intel_output->enc);
intel_output->type = INTEL_OUTPUT_LVDS; 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_encoder_helper_add(encoder, &intel_lvds_helper_funcs);
drm_connector_helper_add(connector, &intel_lvds_connector_helper_funcs); drm_connector_helper_add(connector, &intel_lvds_connector_helper_funcs);
connector->display_info.subpixel_order = SubPixelHorizontalRGB; connector->display_info.subpixel_order = SubPixelHorizontalRGB;
......
...@@ -1458,7 +1458,7 @@ intel_sdvo_multifunc_encoder(struct intel_output *intel_output) ...@@ -1458,7 +1458,7 @@ intel_sdvo_multifunc_encoder(struct intel_output *intel_output)
(SDVO_OUTPUT_RGB0 | SDVO_OUTPUT_RGB1)) (SDVO_OUTPUT_RGB0 | SDVO_OUTPUT_RGB1))
caps++; caps++;
if (sdvo_priv->caps.output_flags & if (sdvo_priv->caps.output_flags &
(SDVO_OUTPUT_SVID0 | SDVO_OUTPUT_SVID0)) (SDVO_OUTPUT_SVID0 | SDVO_OUTPUT_SVID1))
caps++; caps++;
if (sdvo_priv->caps.output_flags & if (sdvo_priv->caps.output_flags &
(SDVO_OUTPUT_CVBS0 | SDVO_OUTPUT_CVBS1)) (SDVO_OUTPUT_CVBS0 | SDVO_OUTPUT_CVBS1))
...@@ -1967,6 +1967,9 @@ intel_sdvo_output_setup(struct intel_output *intel_output, uint16_t flags) ...@@ -1967,6 +1967,9 @@ intel_sdvo_output_setup(struct intel_output *intel_output, uint16_t flags)
intel_sdvo_set_colorimetry(intel_output, intel_sdvo_set_colorimetry(intel_output,
SDVO_COLORIMETRY_RGB256); SDVO_COLORIMETRY_RGB256);
connector->connector_type = DRM_MODE_CONNECTOR_HDMIA; 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) { } else if (flags & SDVO_OUTPUT_SVID0) {
...@@ -1975,11 +1978,14 @@ intel_sdvo_output_setup(struct intel_output *intel_output, uint16_t flags) ...@@ -1975,11 +1978,14 @@ intel_sdvo_output_setup(struct intel_output *intel_output, uint16_t flags)
connector->connector_type = DRM_MODE_CONNECTOR_SVIDEO; connector->connector_type = DRM_MODE_CONNECTOR_SVIDEO;
sdvo_priv->is_tv = true; sdvo_priv->is_tv = true;
intel_output->needs_tv_clock = true; intel_output->needs_tv_clock = true;
intel_output->clone_mask = 1 << INTEL_SDVO_TV_CLONE_BIT;
} else if (flags & SDVO_OUTPUT_RGB0) { } else if (flags & SDVO_OUTPUT_RGB0) {
sdvo_priv->controlled_output = SDVO_OUTPUT_RGB0; sdvo_priv->controlled_output = SDVO_OUTPUT_RGB0;
encoder->encoder_type = DRM_MODE_ENCODER_DAC; encoder->encoder_type = DRM_MODE_ENCODER_DAC;
connector->connector_type = DRM_MODE_CONNECTOR_VGA; 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) { } else if (flags & SDVO_OUTPUT_RGB1) {
sdvo_priv->controlled_output = 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) ...@@ -1991,12 +1997,16 @@ intel_sdvo_output_setup(struct intel_output *intel_output, uint16_t flags)
encoder->encoder_type = DRM_MODE_ENCODER_LVDS; encoder->encoder_type = DRM_MODE_ENCODER_LVDS;
connector->connector_type = DRM_MODE_CONNECTOR_LVDS; connector->connector_type = DRM_MODE_CONNECTOR_LVDS;
sdvo_priv->is_lvds = true; 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) { } else if (flags & SDVO_OUTPUT_LVDS1) {
sdvo_priv->controlled_output = SDVO_OUTPUT_LVDS1; sdvo_priv->controlled_output = SDVO_OUTPUT_LVDS1;
encoder->encoder_type = DRM_MODE_ENCODER_LVDS; encoder->encoder_type = DRM_MODE_ENCODER_LVDS;
connector->connector_type = DRM_MODE_CONNECTOR_LVDS; connector->connector_type = DRM_MODE_CONNECTOR_LVDS;
sdvo_priv->is_lvds = true; sdvo_priv->is_lvds = true;
intel_output->clone_mask = (1 << INTEL_ANALOG_CLONE_BIT) |
(1 << INTEL_SDVO_LVDS_CLONE_BIT);
} else { } else {
unsigned char bytes[2]; unsigned char bytes[2];
...@@ -2009,6 +2019,7 @@ intel_sdvo_output_setup(struct intel_output *intel_output, uint16_t flags) ...@@ -2009,6 +2019,7 @@ intel_sdvo_output_setup(struct intel_output *intel_output, uint16_t flags)
bytes[0], bytes[1]); bytes[0], bytes[1]);
ret = false; ret = false;
} }
intel_output->crtc_mask = (1 << 0) | (1 << 1);
if (ret && registered) if (ret && registered)
ret = drm_sysfs_connector_add(connector) == 0 ? true : false; ret = drm_sysfs_connector_add(connector) == 0 ? true : false;
......
...@@ -1718,6 +1718,7 @@ intel_tv_init(struct drm_device *dev) ...@@ -1718,6 +1718,7 @@ intel_tv_init(struct drm_device *dev)
if (!intel_output) { if (!intel_output) {
return; return;
} }
connector = &intel_output->base; connector = &intel_output->base;
drm_connector_init(dev, connector, &intel_tv_connector_funcs, drm_connector_init(dev, connector, &intel_tv_connector_funcs,
...@@ -1729,6 +1730,7 @@ intel_tv_init(struct drm_device *dev) ...@@ -1729,6 +1730,7 @@ intel_tv_init(struct drm_device *dev)
drm_mode_connector_attach_encoder(&intel_output->base, &intel_output->enc); drm_mode_connector_attach_encoder(&intel_output->base, &intel_output->enc);
tv_priv = (struct intel_tv_priv *)(intel_output + 1); tv_priv = (struct intel_tv_priv *)(intel_output + 1);
intel_output->type = INTEL_OUTPUT_TVOUT; 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_crtcs = ((1 << 0) | (1 << 1));
intel_output->enc.possible_clones = (1 << INTEL_OUTPUT_TVOUT); intel_output->enc.possible_clones = (1 << INTEL_OUTPUT_TVOUT);
intel_output->dev_priv = tv_priv; intel_output->dev_priv = tv_priv;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment