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: Add support for VGA load detection (pre-945). drm/i915: Use an I2C algo to do the flip to SDVO DDC bus. drm/i915: Determine type before initialising connector drm/i915: Return SDVO LVDS VBT mode if no EDID modes are detected. drm/i915: Fetch SDVO LVDS mode lines from VBT, then reserve them i915: support 8xx desktop cursors drm/i915: allocate large pointer arrays with vmalloc
This commit is contained in:
commit
ebd4c994d2
@ -180,7 +180,8 @@ typedef struct drm_i915_private {
|
||||
int backlight_duty_cycle; /* restore backlight to this value */
|
||||
bool panel_wants_dither;
|
||||
struct drm_display_mode *panel_fixed_mode;
|
||||
struct drm_display_mode *vbt_mode; /* if any */
|
||||
struct drm_display_mode *lfp_lvds_vbt_mode; /* if any */
|
||||
struct drm_display_mode *sdvo_lvds_vbt_mode; /* if any */
|
||||
|
||||
/* Feature bits from the VBIOS */
|
||||
unsigned int int_tv_support:1;
|
||||
|
@ -349,7 +349,7 @@ i915_gem_shmem_pread_slow(struct drm_device *dev, struct drm_gem_object *obj,
|
||||
last_data_page = (data_ptr + args->size - 1) / PAGE_SIZE;
|
||||
num_pages = last_data_page - first_data_page + 1;
|
||||
|
||||
user_pages = kcalloc(num_pages, sizeof(struct page *), GFP_KERNEL);
|
||||
user_pages = drm_calloc_large(num_pages, sizeof(struct page *));
|
||||
if (user_pages == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
@ -429,7 +429,7 @@ fail_put_user_pages:
|
||||
SetPageDirty(user_pages[i]);
|
||||
page_cache_release(user_pages[i]);
|
||||
}
|
||||
kfree(user_pages);
|
||||
drm_free_large(user_pages);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -649,7 +649,7 @@ i915_gem_gtt_pwrite_slow(struct drm_device *dev, struct drm_gem_object *obj,
|
||||
last_data_page = (data_ptr + args->size - 1) / PAGE_SIZE;
|
||||
num_pages = last_data_page - first_data_page + 1;
|
||||
|
||||
user_pages = kcalloc(num_pages, sizeof(struct page *), GFP_KERNEL);
|
||||
user_pages = drm_calloc_large(num_pages, sizeof(struct page *));
|
||||
if (user_pages == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
@ -719,7 +719,7 @@ out_unlock:
|
||||
out_unpin_pages:
|
||||
for (i = 0; i < pinned_pages; i++)
|
||||
page_cache_release(user_pages[i]);
|
||||
kfree(user_pages);
|
||||
drm_free_large(user_pages);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -824,7 +824,7 @@ i915_gem_shmem_pwrite_slow(struct drm_device *dev, struct drm_gem_object *obj,
|
||||
last_data_page = (data_ptr + args->size - 1) / PAGE_SIZE;
|
||||
num_pages = last_data_page - first_data_page + 1;
|
||||
|
||||
user_pages = kcalloc(num_pages, sizeof(struct page *), GFP_KERNEL);
|
||||
user_pages = drm_calloc_large(num_pages, sizeof(struct page *));
|
||||
if (user_pages == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
@ -902,7 +902,7 @@ fail_unlock:
|
||||
fail_put_user_pages:
|
||||
for (i = 0; i < pinned_pages; i++)
|
||||
page_cache_release(user_pages[i]);
|
||||
kfree(user_pages);
|
||||
drm_free_large(user_pages);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -1145,7 +1145,7 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
return VM_FAULT_SIGBUS;
|
||||
}
|
||||
list_add(&obj_priv->list, &dev_priv->mm.inactive_list);
|
||||
list_add_tail(&obj_priv->list, &dev_priv->mm.inactive_list);
|
||||
}
|
||||
|
||||
/* Need a new fence register? */
|
||||
@ -1375,7 +1375,7 @@ i915_gem_mmap_gtt_ioctl(struct drm_device *dev, void *data,
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
return ret;
|
||||
}
|
||||
list_add(&obj_priv->list, &dev_priv->mm.inactive_list);
|
||||
list_add_tail(&obj_priv->list, &dev_priv->mm.inactive_list);
|
||||
}
|
||||
|
||||
drm_gem_object_unreference(obj);
|
||||
@ -1408,9 +1408,7 @@ i915_gem_object_put_pages(struct drm_gem_object *obj)
|
||||
}
|
||||
obj_priv->dirty = 0;
|
||||
|
||||
drm_free(obj_priv->pages,
|
||||
page_count * sizeof(struct page *),
|
||||
DRM_MEM_DRIVER);
|
||||
drm_free_large(obj_priv->pages);
|
||||
obj_priv->pages = NULL;
|
||||
}
|
||||
|
||||
@ -2024,8 +2022,7 @@ i915_gem_object_get_pages(struct drm_gem_object *obj)
|
||||
*/
|
||||
page_count = obj->size / PAGE_SIZE;
|
||||
BUG_ON(obj_priv->pages != NULL);
|
||||
obj_priv->pages = drm_calloc(page_count, sizeof(struct page *),
|
||||
DRM_MEM_DRIVER);
|
||||
obj_priv->pages = drm_calloc_large(page_count, sizeof(struct page *));
|
||||
if (obj_priv->pages == NULL) {
|
||||
DRM_ERROR("Faled to allocate page list\n");
|
||||
obj_priv->pages_refcount--;
|
||||
@ -3111,7 +3108,7 @@ i915_gem_get_relocs_from_user(struct drm_i915_gem_exec_object *exec_list,
|
||||
reloc_count += exec_list[i].relocation_count;
|
||||
}
|
||||
|
||||
*relocs = drm_calloc(reloc_count, sizeof(**relocs), DRM_MEM_DRIVER);
|
||||
*relocs = drm_calloc_large(reloc_count, sizeof(**relocs));
|
||||
if (*relocs == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
@ -3125,8 +3122,7 @@ i915_gem_get_relocs_from_user(struct drm_i915_gem_exec_object *exec_list,
|
||||
exec_list[i].relocation_count *
|
||||
sizeof(**relocs));
|
||||
if (ret != 0) {
|
||||
drm_free(*relocs, reloc_count * sizeof(**relocs),
|
||||
DRM_MEM_DRIVER);
|
||||
drm_free_large(*relocs);
|
||||
*relocs = NULL;
|
||||
return -EFAULT;
|
||||
}
|
||||
@ -3165,7 +3161,7 @@ i915_gem_put_relocs_to_user(struct drm_i915_gem_exec_object *exec_list,
|
||||
}
|
||||
|
||||
err:
|
||||
drm_free(relocs, reloc_count * sizeof(*relocs), DRM_MEM_DRIVER);
|
||||
drm_free_large(relocs);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -3198,10 +3194,8 @@ i915_gem_execbuffer(struct drm_device *dev, void *data,
|
||||
return -EINVAL;
|
||||
}
|
||||
/* Copy in the exec list from userland */
|
||||
exec_list = drm_calloc(sizeof(*exec_list), args->buffer_count,
|
||||
DRM_MEM_DRIVER);
|
||||
object_list = drm_calloc(sizeof(*object_list), args->buffer_count,
|
||||
DRM_MEM_DRIVER);
|
||||
exec_list = drm_calloc_large(sizeof(*exec_list), args->buffer_count);
|
||||
object_list = drm_calloc_large(sizeof(*object_list), args->buffer_count);
|
||||
if (exec_list == NULL || object_list == NULL) {
|
||||
DRM_ERROR("Failed to allocate exec or object list "
|
||||
"for %d buffers\n",
|
||||
@ -3462,10 +3456,8 @@ err:
|
||||
}
|
||||
|
||||
pre_mutex_err:
|
||||
drm_free(object_list, sizeof(*object_list) * args->buffer_count,
|
||||
DRM_MEM_DRIVER);
|
||||
drm_free(exec_list, sizeof(*exec_list) * args->buffer_count,
|
||||
DRM_MEM_DRIVER);
|
||||
drm_free_large(object_list);
|
||||
drm_free_large(exec_list);
|
||||
drm_free(cliprects, sizeof(*cliprects) * args->num_cliprects,
|
||||
DRM_MEM_DRIVER);
|
||||
|
||||
|
@ -1410,9 +1410,25 @@
|
||||
|
||||
/* Cursor A & B regs */
|
||||
#define CURACNTR 0x70080
|
||||
/* Old style CUR*CNTR flags (desktop 8xx) */
|
||||
#define CURSOR_ENABLE 0x80000000
|
||||
#define CURSOR_GAMMA_ENABLE 0x40000000
|
||||
#define CURSOR_STRIDE_MASK 0x30000000
|
||||
#define CURSOR_FORMAT_SHIFT 24
|
||||
#define CURSOR_FORMAT_MASK (0x07 << CURSOR_FORMAT_SHIFT)
|
||||
#define CURSOR_FORMAT_2C (0x00 << CURSOR_FORMAT_SHIFT)
|
||||
#define CURSOR_FORMAT_3C (0x01 << CURSOR_FORMAT_SHIFT)
|
||||
#define CURSOR_FORMAT_4C (0x02 << CURSOR_FORMAT_SHIFT)
|
||||
#define CURSOR_FORMAT_ARGB (0x04 << CURSOR_FORMAT_SHIFT)
|
||||
#define CURSOR_FORMAT_XRGB (0x05 << CURSOR_FORMAT_SHIFT)
|
||||
/* New style CUR*CNTR flags */
|
||||
#define CURSOR_MODE 0x27
|
||||
#define CURSOR_MODE_DISABLE 0x00
|
||||
#define CURSOR_MODE_64_32B_AX 0x07
|
||||
#define CURSOR_MODE_64_ARGB_AX ((1 << 5) | CURSOR_MODE_64_32B_AX)
|
||||
#define MCURSOR_PIPE_SELECT (1 << 28)
|
||||
#define MCURSOR_PIPE_A 0x00
|
||||
#define MCURSOR_PIPE_B (1 << 28)
|
||||
#define MCURSOR_GAMMA_ENABLE (1 << 26)
|
||||
#define CURABASE 0x70084
|
||||
#define CURAPOS 0x70088
|
||||
@ -1420,6 +1436,7 @@
|
||||
#define CURSOR_POS_SIGN 0x8000
|
||||
#define CURSOR_X_SHIFT 0
|
||||
#define CURSOR_Y_SHIFT 16
|
||||
#define CURSIZE 0x700a0
|
||||
#define CURBCNTR 0x700c0
|
||||
#define CURBBASE 0x700c4
|
||||
#define CURBPOS 0x700c8
|
||||
|
@ -57,9 +57,43 @@ find_section(struct bdb_header *bdb, int section_id)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Try to find panel data */
|
||||
static void
|
||||
parse_panel_data(struct drm_i915_private *dev_priv, struct bdb_header *bdb)
|
||||
fill_detail_timing_data(struct drm_display_mode *panel_fixed_mode,
|
||||
struct lvds_dvo_timing *dvo_timing)
|
||||
{
|
||||
panel_fixed_mode->hdisplay = (dvo_timing->hactive_hi << 8) |
|
||||
dvo_timing->hactive_lo;
|
||||
panel_fixed_mode->hsync_start = panel_fixed_mode->hdisplay +
|
||||
((dvo_timing->hsync_off_hi << 8) | dvo_timing->hsync_off_lo);
|
||||
panel_fixed_mode->hsync_end = panel_fixed_mode->hsync_start +
|
||||
dvo_timing->hsync_pulse_width;
|
||||
panel_fixed_mode->htotal = panel_fixed_mode->hdisplay +
|
||||
((dvo_timing->hblank_hi << 8) | dvo_timing->hblank_lo);
|
||||
|
||||
panel_fixed_mode->vdisplay = (dvo_timing->vactive_hi << 8) |
|
||||
dvo_timing->vactive_lo;
|
||||
panel_fixed_mode->vsync_start = panel_fixed_mode->vdisplay +
|
||||
dvo_timing->vsync_off;
|
||||
panel_fixed_mode->vsync_end = panel_fixed_mode->vsync_start +
|
||||
dvo_timing->vsync_pulse_width;
|
||||
panel_fixed_mode->vtotal = panel_fixed_mode->vdisplay +
|
||||
((dvo_timing->vblank_hi << 8) | dvo_timing->vblank_lo);
|
||||
panel_fixed_mode->clock = dvo_timing->clock * 10;
|
||||
panel_fixed_mode->type = DRM_MODE_TYPE_PREFERRED;
|
||||
|
||||
/* Some VBTs have bogus h/vtotal values */
|
||||
if (panel_fixed_mode->hsync_end > panel_fixed_mode->htotal)
|
||||
panel_fixed_mode->htotal = panel_fixed_mode->hsync_end + 1;
|
||||
if (panel_fixed_mode->vsync_end > panel_fixed_mode->vtotal)
|
||||
panel_fixed_mode->vtotal = panel_fixed_mode->vsync_end + 1;
|
||||
|
||||
drm_mode_set_name(panel_fixed_mode);
|
||||
}
|
||||
|
||||
/* Try to find integrated panel data */
|
||||
static void
|
||||
parse_lfp_panel_data(struct drm_i915_private *dev_priv,
|
||||
struct bdb_header *bdb)
|
||||
{
|
||||
struct bdb_lvds_options *lvds_options;
|
||||
struct bdb_lvds_lfp_data *lvds_lfp_data;
|
||||
@ -91,35 +125,9 @@ parse_panel_data(struct drm_i915_private *dev_priv, struct bdb_header *bdb)
|
||||
panel_fixed_mode = drm_calloc(1, sizeof(*panel_fixed_mode),
|
||||
DRM_MEM_DRIVER);
|
||||
|
||||
panel_fixed_mode->hdisplay = (dvo_timing->hactive_hi << 8) |
|
||||
dvo_timing->hactive_lo;
|
||||
panel_fixed_mode->hsync_start = panel_fixed_mode->hdisplay +
|
||||
((dvo_timing->hsync_off_hi << 8) | dvo_timing->hsync_off_lo);
|
||||
panel_fixed_mode->hsync_end = panel_fixed_mode->hsync_start +
|
||||
dvo_timing->hsync_pulse_width;
|
||||
panel_fixed_mode->htotal = panel_fixed_mode->hdisplay +
|
||||
((dvo_timing->hblank_hi << 8) | dvo_timing->hblank_lo);
|
||||
fill_detail_timing_data(panel_fixed_mode, dvo_timing);
|
||||
|
||||
panel_fixed_mode->vdisplay = (dvo_timing->vactive_hi << 8) |
|
||||
dvo_timing->vactive_lo;
|
||||
panel_fixed_mode->vsync_start = panel_fixed_mode->vdisplay +
|
||||
dvo_timing->vsync_off;
|
||||
panel_fixed_mode->vsync_end = panel_fixed_mode->vsync_start +
|
||||
dvo_timing->vsync_pulse_width;
|
||||
panel_fixed_mode->vtotal = panel_fixed_mode->vdisplay +
|
||||
((dvo_timing->vblank_hi << 8) | dvo_timing->vblank_lo);
|
||||
panel_fixed_mode->clock = dvo_timing->clock * 10;
|
||||
panel_fixed_mode->type = DRM_MODE_TYPE_PREFERRED;
|
||||
|
||||
/* Some VBTs have bogus h/vtotal values */
|
||||
if (panel_fixed_mode->hsync_end > panel_fixed_mode->htotal)
|
||||
panel_fixed_mode->htotal = panel_fixed_mode->hsync_end + 1;
|
||||
if (panel_fixed_mode->vsync_end > panel_fixed_mode->vtotal)
|
||||
panel_fixed_mode->vtotal = panel_fixed_mode->vsync_end + 1;
|
||||
|
||||
drm_mode_set_name(panel_fixed_mode);
|
||||
|
||||
dev_priv->vbt_mode = panel_fixed_mode;
|
||||
dev_priv->lfp_lvds_vbt_mode = panel_fixed_mode;
|
||||
|
||||
DRM_DEBUG("Found panel mode in BIOS VBT tables:\n");
|
||||
drm_mode_debug_printmodeline(panel_fixed_mode);
|
||||
@ -127,6 +135,39 @@ parse_panel_data(struct drm_i915_private *dev_priv, struct bdb_header *bdb)
|
||||
return;
|
||||
}
|
||||
|
||||
/* Try to find sdvo panel data */
|
||||
static void
|
||||
parse_sdvo_panel_data(struct drm_i915_private *dev_priv,
|
||||
struct bdb_header *bdb)
|
||||
{
|
||||
struct bdb_sdvo_lvds_options *sdvo_lvds_options;
|
||||
struct lvds_dvo_timing *dvo_timing;
|
||||
struct drm_display_mode *panel_fixed_mode;
|
||||
|
||||
dev_priv->sdvo_lvds_vbt_mode = NULL;
|
||||
|
||||
sdvo_lvds_options = find_section(bdb, BDB_SDVO_LVDS_OPTIONS);
|
||||
if (!sdvo_lvds_options)
|
||||
return;
|
||||
|
||||
dvo_timing = find_section(bdb, BDB_SDVO_PANEL_DTDS);
|
||||
if (!dvo_timing)
|
||||
return;
|
||||
|
||||
panel_fixed_mode = drm_calloc(1, sizeof(*panel_fixed_mode),
|
||||
DRM_MEM_DRIVER);
|
||||
|
||||
if (!panel_fixed_mode)
|
||||
return;
|
||||
|
||||
fill_detail_timing_data(panel_fixed_mode,
|
||||
dvo_timing + sdvo_lvds_options->panel_type);
|
||||
|
||||
dev_priv->sdvo_lvds_vbt_mode = panel_fixed_mode;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
parse_general_features(struct drm_i915_private *dev_priv,
|
||||
struct bdb_header *bdb)
|
||||
@ -199,7 +240,8 @@ intel_init_bios(struct drm_device *dev)
|
||||
|
||||
/* Grab useful general definitions */
|
||||
parse_general_features(dev_priv, bdb);
|
||||
parse_panel_data(dev_priv, bdb);
|
||||
parse_lfp_panel_data(dev_priv, bdb);
|
||||
parse_sdvo_panel_data(dev_priv, bdb);
|
||||
|
||||
pci_unmap_rom(pdev, bios);
|
||||
|
||||
|
@ -279,6 +279,23 @@ struct vch_bdb_22 {
|
||||
struct vch_panel_data panels[16];
|
||||
} __attribute__((packed));
|
||||
|
||||
struct bdb_sdvo_lvds_options {
|
||||
u8 panel_backlight;
|
||||
u8 h40_set_panel_type;
|
||||
u8 panel_type;
|
||||
u8 ssc_clk_freq;
|
||||
u16 als_low_trip;
|
||||
u16 als_high_trip;
|
||||
u8 sclalarcoeff_tab_row_num;
|
||||
u8 sclalarcoeff_tab_row_size;
|
||||
u8 coefficient[8];
|
||||
u8 panel_misc_bits_1;
|
||||
u8 panel_misc_bits_2;
|
||||
u8 panel_misc_bits_3;
|
||||
u8 panel_misc_bits_4;
|
||||
} __attribute__((packed));
|
||||
|
||||
|
||||
bool intel_init_bios(struct drm_device *dev);
|
||||
|
||||
/*
|
||||
|
@ -198,9 +198,142 @@ static bool intel_crt_detect_ddc(struct drm_connector *connector)
|
||||
return intel_ddc_probe(intel_output);
|
||||
}
|
||||
|
||||
static enum drm_connector_status
|
||||
intel_crt_load_detect(struct drm_crtc *crtc, struct intel_output *intel_output)
|
||||
{
|
||||
struct drm_encoder *encoder = &intel_output->enc;
|
||||
struct drm_device *dev = encoder->dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
|
||||
uint32_t pipe = intel_crtc->pipe;
|
||||
uint32_t save_bclrpat;
|
||||
uint32_t save_vtotal;
|
||||
uint32_t vtotal, vactive;
|
||||
uint32_t vsample;
|
||||
uint32_t vblank, vblank_start, vblank_end;
|
||||
uint32_t dsl;
|
||||
uint32_t bclrpat_reg;
|
||||
uint32_t vtotal_reg;
|
||||
uint32_t vblank_reg;
|
||||
uint32_t vsync_reg;
|
||||
uint32_t pipeconf_reg;
|
||||
uint32_t pipe_dsl_reg;
|
||||
uint8_t st00;
|
||||
enum drm_connector_status status;
|
||||
|
||||
if (pipe == 0) {
|
||||
bclrpat_reg = BCLRPAT_A;
|
||||
vtotal_reg = VTOTAL_A;
|
||||
vblank_reg = VBLANK_A;
|
||||
vsync_reg = VSYNC_A;
|
||||
pipeconf_reg = PIPEACONF;
|
||||
pipe_dsl_reg = PIPEADSL;
|
||||
} else {
|
||||
bclrpat_reg = BCLRPAT_B;
|
||||
vtotal_reg = VTOTAL_B;
|
||||
vblank_reg = VBLANK_B;
|
||||
vsync_reg = VSYNC_B;
|
||||
pipeconf_reg = PIPEBCONF;
|
||||
pipe_dsl_reg = PIPEBDSL;
|
||||
}
|
||||
|
||||
save_bclrpat = I915_READ(bclrpat_reg);
|
||||
save_vtotal = I915_READ(vtotal_reg);
|
||||
vblank = I915_READ(vblank_reg);
|
||||
|
||||
vtotal = ((save_vtotal >> 16) & 0xfff) + 1;
|
||||
vactive = (save_vtotal & 0x7ff) + 1;
|
||||
|
||||
vblank_start = (vblank & 0xfff) + 1;
|
||||
vblank_end = ((vblank >> 16) & 0xfff) + 1;
|
||||
|
||||
/* Set the border color to purple. */
|
||||
I915_WRITE(bclrpat_reg, 0x500050);
|
||||
|
||||
if (IS_I9XX(dev)) {
|
||||
uint32_t pipeconf = I915_READ(pipeconf_reg);
|
||||
I915_WRITE(pipeconf_reg, pipeconf | PIPECONF_FORCE_BORDER);
|
||||
/* Wait for next Vblank to substitue
|
||||
* border color for Color info */
|
||||
intel_wait_for_vblank(dev);
|
||||
st00 = I915_READ8(VGA_MSR_WRITE);
|
||||
status = ((st00 & (1 << 4)) != 0) ?
|
||||
connector_status_connected :
|
||||
connector_status_disconnected;
|
||||
|
||||
I915_WRITE(pipeconf_reg, pipeconf);
|
||||
} else {
|
||||
bool restore_vblank = false;
|
||||
int count, detect;
|
||||
|
||||
/*
|
||||
* If there isn't any border, add some.
|
||||
* Yes, this will flicker
|
||||
*/
|
||||
if (vblank_start <= vactive && vblank_end >= vtotal) {
|
||||
uint32_t vsync = I915_READ(vsync_reg);
|
||||
uint32_t vsync_start = (vsync & 0xffff) + 1;
|
||||
|
||||
vblank_start = vsync_start;
|
||||
I915_WRITE(vblank_reg,
|
||||
(vblank_start - 1) |
|
||||
((vblank_end - 1) << 16));
|
||||
restore_vblank = true;
|
||||
}
|
||||
/* sample in the vertical border, selecting the larger one */
|
||||
if (vblank_start - vactive >= vtotal - vblank_end)
|
||||
vsample = (vblank_start + vactive) >> 1;
|
||||
else
|
||||
vsample = (vtotal + vblank_end) >> 1;
|
||||
|
||||
/*
|
||||
* Wait for the border to be displayed
|
||||
*/
|
||||
while (I915_READ(pipe_dsl_reg) >= vactive)
|
||||
;
|
||||
while ((dsl = I915_READ(pipe_dsl_reg)) <= vsample)
|
||||
;
|
||||
/*
|
||||
* Watch ST00 for an entire scanline
|
||||
*/
|
||||
detect = 0;
|
||||
count = 0;
|
||||
do {
|
||||
count++;
|
||||
/* Read the ST00 VGA status register */
|
||||
st00 = I915_READ8(VGA_MSR_WRITE);
|
||||
if (st00 & (1 << 4))
|
||||
detect++;
|
||||
} while ((I915_READ(pipe_dsl_reg) == dsl));
|
||||
|
||||
/* restore vblank if necessary */
|
||||
if (restore_vblank)
|
||||
I915_WRITE(vblank_reg, vblank);
|
||||
/*
|
||||
* If more than 3/4 of the scanline detected a monitor,
|
||||
* then it is assumed to be present. This works even on i830,
|
||||
* where there isn't any way to force the border color across
|
||||
* the screen
|
||||
*/
|
||||
status = detect * 4 > count * 3 ?
|
||||
connector_status_connected :
|
||||
connector_status_disconnected;
|
||||
}
|
||||
|
||||
/* Restore previous settings */
|
||||
I915_WRITE(bclrpat_reg, save_bclrpat);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static enum drm_connector_status intel_crt_detect(struct drm_connector *connector)
|
||||
{
|
||||
struct drm_device *dev = connector->dev;
|
||||
struct intel_output *intel_output = to_intel_output(connector);
|
||||
struct drm_encoder *encoder = &intel_output->enc;
|
||||
struct drm_crtc *crtc;
|
||||
int dpms_mode;
|
||||
enum drm_connector_status status;
|
||||
|
||||
if (IS_I9XX(dev) && !IS_I915G(dev) && !IS_I915GM(dev)) {
|
||||
if (intel_crt_detect_hotplug(connector))
|
||||
@ -212,8 +345,20 @@ static enum drm_connector_status intel_crt_detect(struct drm_connector *connecto
|
||||
if (intel_crt_detect_ddc(connector))
|
||||
return connector_status_connected;
|
||||
|
||||
/* TODO use load detect */
|
||||
return connector_status_unknown;
|
||||
/* for pre-945g platforms use load detect */
|
||||
if (encoder->crtc && encoder->crtc->enabled) {
|
||||
status = intel_crt_load_detect(encoder->crtc, intel_output);
|
||||
} else {
|
||||
crtc = intel_get_load_detect_pipe(intel_output,
|
||||
NULL, &dpms_mode);
|
||||
if (crtc) {
|
||||
status = intel_crt_load_detect(crtc, intel_output);
|
||||
intel_release_load_detect_pipe(intel_output, dpms_mode);
|
||||
} else
|
||||
status = connector_status_unknown;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static void intel_crt_destroy(struct drm_connector *connector)
|
||||
|
@ -1357,7 +1357,7 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,
|
||||
int pipe = intel_crtc->pipe;
|
||||
uint32_t control = (pipe == 0) ? CURACNTR : CURBCNTR;
|
||||
uint32_t base = (pipe == 0) ? CURABASE : CURBBASE;
|
||||
uint32_t temp;
|
||||
uint32_t temp = I915_READ(control);
|
||||
size_t addr;
|
||||
int ret;
|
||||
|
||||
@ -1366,7 +1366,12 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,
|
||||
/* if we want to turn off the cursor ignore width and height */
|
||||
if (!handle) {
|
||||
DRM_DEBUG("cursor off\n");
|
||||
temp = CURSOR_MODE_DISABLE;
|
||||
if (IS_MOBILE(dev) || IS_I9XX(dev)) {
|
||||
temp &= ~(CURSOR_MODE | MCURSOR_GAMMA_ENABLE);
|
||||
temp |= CURSOR_MODE_DISABLE;
|
||||
} else {
|
||||
temp &= ~(CURSOR_ENABLE | CURSOR_GAMMA_ENABLE);
|
||||
}
|
||||
addr = 0;
|
||||
bo = NULL;
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
@ -1409,10 +1414,19 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,
|
||||
addr = obj_priv->phys_obj->handle->busaddr;
|
||||
}
|
||||
|
||||
temp = 0;
|
||||
/* set the pipe for the cursor */
|
||||
temp |= (pipe << 28);
|
||||
temp |= CURSOR_MODE_64_ARGB_AX | MCURSOR_GAMMA_ENABLE;
|
||||
if (!IS_I9XX(dev))
|
||||
I915_WRITE(CURSIZE, (height << 12) | width);
|
||||
|
||||
/* Hooray for CUR*CNTR differences */
|
||||
if (IS_MOBILE(dev) || IS_I9XX(dev)) {
|
||||
temp &= ~(CURSOR_MODE | MCURSOR_PIPE_SELECT);
|
||||
temp |= CURSOR_MODE_64_ARGB_AX | MCURSOR_GAMMA_ENABLE;
|
||||
temp |= (pipe << 28); /* Connect to correct pipe */
|
||||
} else {
|
||||
temp &= ~(CURSOR_FORMAT_MASK);
|
||||
temp |= CURSOR_ENABLE;
|
||||
temp |= CURSOR_FORMAT_ARGB | CURSOR_GAMMA_ENABLE;
|
||||
}
|
||||
|
||||
finish:
|
||||
I915_WRITE(control, temp);
|
||||
|
@ -511,10 +511,10 @@ void intel_lvds_init(struct drm_device *dev)
|
||||
}
|
||||
|
||||
/* Failed to get EDID, what about VBT? */
|
||||
if (dev_priv->vbt_mode) {
|
||||
if (dev_priv->lfp_lvds_vbt_mode) {
|
||||
mutex_lock(&dev->mode_config.mutex);
|
||||
dev_priv->panel_fixed_mode =
|
||||
drm_mode_duplicate(dev, dev_priv->vbt_mode);
|
||||
drm_mode_duplicate(dev, dev_priv->lfp_lvds_vbt_mode);
|
||||
mutex_unlock(&dev->mode_config.mutex);
|
||||
if (dev_priv->panel_fixed_mode) {
|
||||
dev_priv->panel_fixed_mode->type |=
|
||||
|
@ -69,6 +69,10 @@ struct intel_sdvo_priv {
|
||||
* This is set if we treat the device as HDMI, instead of DVI.
|
||||
*/
|
||||
bool is_hdmi;
|
||||
/**
|
||||
* This is set if we detect output of sdvo device as LVDS.
|
||||
*/
|
||||
bool is_lvds;
|
||||
|
||||
/**
|
||||
* Returned SDTV resolutions allowed for the current format, if the
|
||||
@ -1398,10 +1402,8 @@ static enum drm_connector_status intel_sdvo_detect(struct drm_connector *connect
|
||||
static void intel_sdvo_get_ddc_modes(struct drm_connector *connector)
|
||||
{
|
||||
struct intel_output *intel_output = to_intel_output(connector);
|
||||
struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
|
||||
|
||||
/* set the bus switch and get the modes */
|
||||
intel_sdvo_set_control_bus_switch(intel_output, sdvo_priv->ddc_bus);
|
||||
intel_ddc_get_modes(intel_output);
|
||||
|
||||
#if 0
|
||||
@ -1543,6 +1545,37 @@ static void intel_sdvo_get_tv_modes(struct drm_connector *connector)
|
||||
}
|
||||
}
|
||||
|
||||
static void intel_sdvo_get_lvds_modes(struct drm_connector *connector)
|
||||
{
|
||||
struct intel_output *intel_output = to_intel_output(connector);
|
||||
struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
|
||||
struct drm_i915_private *dev_priv = connector->dev->dev_private;
|
||||
|
||||
/*
|
||||
* Attempt to get the mode list from DDC.
|
||||
* Assume that the preferred modes are
|
||||
* arranged in priority order.
|
||||
*/
|
||||
/* set the bus switch and get the modes */
|
||||
intel_sdvo_set_control_bus_switch(intel_output, sdvo_priv->ddc_bus);
|
||||
intel_ddc_get_modes(intel_output);
|
||||
if (list_empty(&connector->probed_modes) == false)
|
||||
return;
|
||||
|
||||
/* Fetch modes from VBT */
|
||||
if (dev_priv->sdvo_lvds_vbt_mode != NULL) {
|
||||
struct drm_display_mode *newmode;
|
||||
newmode = drm_mode_duplicate(connector->dev,
|
||||
dev_priv->sdvo_lvds_vbt_mode);
|
||||
if (newmode != NULL) {
|
||||
/* Guarantee the mode is preferred */
|
||||
newmode->type = (DRM_MODE_TYPE_PREFERRED |
|
||||
DRM_MODE_TYPE_DRIVER);
|
||||
drm_mode_probed_add(connector, newmode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int intel_sdvo_get_modes(struct drm_connector *connector)
|
||||
{
|
||||
struct intel_output *output = to_intel_output(connector);
|
||||
@ -1550,6 +1583,8 @@ static int intel_sdvo_get_modes(struct drm_connector *connector)
|
||||
|
||||
if (sdvo_priv->is_tv)
|
||||
intel_sdvo_get_tv_modes(connector);
|
||||
else if (sdvo_priv->is_lvds == true)
|
||||
intel_sdvo_get_lvds_modes(connector);
|
||||
else
|
||||
intel_sdvo_get_ddc_modes(connector);
|
||||
|
||||
@ -1564,6 +1599,9 @@ static void intel_sdvo_destroy(struct drm_connector *connector)
|
||||
|
||||
if (intel_output->i2c_bus)
|
||||
intel_i2c_destroy(intel_output->i2c_bus);
|
||||
if (intel_output->ddc_bus)
|
||||
intel_i2c_destroy(intel_output->ddc_bus);
|
||||
|
||||
drm_sysfs_connector_remove(connector);
|
||||
drm_connector_cleanup(connector);
|
||||
kfree(intel_output);
|
||||
@ -1660,12 +1698,56 @@ intel_sdvo_get_digital_encoding_mode(struct intel_output *output)
|
||||
return true;
|
||||
}
|
||||
|
||||
static struct intel_output *
|
||||
intel_sdvo_chan_to_intel_output(struct intel_i2c_chan *chan)
|
||||
{
|
||||
struct drm_device *dev = chan->drm_dev;
|
||||
struct drm_connector *connector;
|
||||
struct intel_output *intel_output = NULL;
|
||||
|
||||
list_for_each_entry(connector,
|
||||
&dev->mode_config.connector_list, head) {
|
||||
if (to_intel_output(connector)->ddc_bus == chan) {
|
||||
intel_output = to_intel_output(connector);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return intel_output;
|
||||
}
|
||||
|
||||
static int intel_sdvo_master_xfer(struct i2c_adapter *i2c_adap,
|
||||
struct i2c_msg msgs[], int num)
|
||||
{
|
||||
struct intel_output *intel_output;
|
||||
struct intel_sdvo_priv *sdvo_priv;
|
||||
struct i2c_algo_bit_data *algo_data;
|
||||
struct i2c_algorithm *algo;
|
||||
|
||||
algo_data = (struct i2c_algo_bit_data *)i2c_adap->algo_data;
|
||||
intel_output =
|
||||
intel_sdvo_chan_to_intel_output(
|
||||
(struct intel_i2c_chan *)(algo_data->data));
|
||||
if (intel_output == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
sdvo_priv = intel_output->dev_priv;
|
||||
algo = (struct i2c_algorithm *)intel_output->i2c_bus->adapter.algo;
|
||||
|
||||
intel_sdvo_set_control_bus_switch(intel_output, sdvo_priv->ddc_bus);
|
||||
return algo->master_xfer(i2c_adap, msgs, num);
|
||||
}
|
||||
|
||||
static struct i2c_algorithm intel_sdvo_i2c_bit_algo = {
|
||||
.master_xfer = intel_sdvo_master_xfer,
|
||||
};
|
||||
|
||||
bool intel_sdvo_init(struct drm_device *dev, int output_device)
|
||||
{
|
||||
struct drm_connector *connector;
|
||||
struct intel_output *intel_output;
|
||||
struct intel_sdvo_priv *sdvo_priv;
|
||||
struct intel_i2c_chan *i2cbus = NULL;
|
||||
struct intel_i2c_chan *ddcbus = NULL;
|
||||
int connector_type;
|
||||
u8 ch[0x40];
|
||||
int i;
|
||||
@ -1676,17 +1758,9 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device)
|
||||
return false;
|
||||
}
|
||||
|
||||
connector = &intel_output->base;
|
||||
|
||||
drm_connector_init(dev, connector, &intel_sdvo_connector_funcs,
|
||||
DRM_MODE_CONNECTOR_Unknown);
|
||||
drm_connector_helper_add(connector, &intel_sdvo_connector_helper_funcs);
|
||||
sdvo_priv = (struct intel_sdvo_priv *)(intel_output + 1);
|
||||
intel_output->type = INTEL_OUTPUT_SDVO;
|
||||
|
||||
connector->interlace_allowed = 0;
|
||||
connector->doublescan_allowed = 0;
|
||||
|
||||
/* setup the DDC bus. */
|
||||
if (output_device == SDVOB)
|
||||
i2cbus = intel_i2c_create(dev, GPIOE, "SDVOCTRL_E for SDVOB");
|
||||
@ -1694,7 +1768,7 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device)
|
||||
i2cbus = intel_i2c_create(dev, GPIOE, "SDVOCTRL_E for SDVOC");
|
||||
|
||||
if (!i2cbus)
|
||||
goto err_connector;
|
||||
goto err_inteloutput;
|
||||
|
||||
sdvo_priv->i2c_bus = i2cbus;
|
||||
|
||||
@ -1710,7 +1784,6 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device)
|
||||
intel_output->i2c_bus = i2cbus;
|
||||
intel_output->dev_priv = sdvo_priv;
|
||||
|
||||
|
||||
/* Read the regs to test if we can talk to the device */
|
||||
for (i = 0; i < 0x40; i++) {
|
||||
if (!intel_sdvo_read_byte(intel_output, i, &ch[i])) {
|
||||
@ -1720,6 +1793,22 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device)
|
||||
}
|
||||
}
|
||||
|
||||
/* setup the DDC bus. */
|
||||
if (output_device == SDVOB)
|
||||
ddcbus = intel_i2c_create(dev, GPIOE, "SDVOB DDC BUS");
|
||||
else
|
||||
ddcbus = intel_i2c_create(dev, GPIOE, "SDVOC DDC BUS");
|
||||
|
||||
if (ddcbus == NULL)
|
||||
goto err_i2c;
|
||||
|
||||
intel_sdvo_i2c_bit_algo.functionality =
|
||||
intel_output->i2c_bus->adapter.algo->functionality;
|
||||
ddcbus->adapter.algo = &intel_sdvo_i2c_bit_algo;
|
||||
intel_output->ddc_bus = ddcbus;
|
||||
|
||||
/* In defaut case sdvo lvds is false */
|
||||
sdvo_priv->is_lvds = false;
|
||||
intel_sdvo_get_capabilities(intel_output, &sdvo_priv->caps);
|
||||
|
||||
if (sdvo_priv->caps.output_flags &
|
||||
@ -1729,7 +1818,6 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device)
|
||||
else
|
||||
sdvo_priv->controlled_output = SDVO_OUTPUT_TMDS1;
|
||||
|
||||
connector->display_info.subpixel_order = SubPixelHorizontalRGB;
|
||||
encoder_type = DRM_MODE_ENCODER_TMDS;
|
||||
connector_type = DRM_MODE_CONNECTOR_DVID;
|
||||
|
||||
@ -1747,7 +1835,6 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device)
|
||||
else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_SVID0)
|
||||
{
|
||||
sdvo_priv->controlled_output = SDVO_OUTPUT_SVID0;
|
||||
connector->display_info.subpixel_order = SubPixelHorizontalRGB;
|
||||
encoder_type = DRM_MODE_ENCODER_TVDAC;
|
||||
connector_type = DRM_MODE_CONNECTOR_SVIDEO;
|
||||
sdvo_priv->is_tv = true;
|
||||
@ -1756,30 +1843,28 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device)
|
||||
else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_RGB0)
|
||||
{
|
||||
sdvo_priv->controlled_output = SDVO_OUTPUT_RGB0;
|
||||
connector->display_info.subpixel_order = SubPixelHorizontalRGB;
|
||||
encoder_type = DRM_MODE_ENCODER_DAC;
|
||||
connector_type = DRM_MODE_CONNECTOR_VGA;
|
||||
}
|
||||
else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_RGB1)
|
||||
{
|
||||
sdvo_priv->controlled_output = SDVO_OUTPUT_RGB1;
|
||||
connector->display_info.subpixel_order = SubPixelHorizontalRGB;
|
||||
encoder_type = DRM_MODE_ENCODER_DAC;
|
||||
connector_type = DRM_MODE_CONNECTOR_VGA;
|
||||
}
|
||||
else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_LVDS0)
|
||||
{
|
||||
sdvo_priv->controlled_output = SDVO_OUTPUT_LVDS0;
|
||||
connector->display_info.subpixel_order = SubPixelHorizontalRGB;
|
||||
encoder_type = DRM_MODE_ENCODER_LVDS;
|
||||
connector_type = DRM_MODE_CONNECTOR_LVDS;
|
||||
sdvo_priv->is_lvds = true;
|
||||
}
|
||||
else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_LVDS1)
|
||||
{
|
||||
sdvo_priv->controlled_output = SDVO_OUTPUT_LVDS1;
|
||||
connector->display_info.subpixel_order = SubPixelHorizontalRGB;
|
||||
encoder_type = DRM_MODE_ENCODER_LVDS;
|
||||
connector_type = DRM_MODE_CONNECTOR_LVDS;
|
||||
sdvo_priv->is_lvds = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1795,9 +1880,16 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device)
|
||||
goto err_i2c;
|
||||
}
|
||||
|
||||
connector = &intel_output->base;
|
||||
drm_connector_init(dev, connector, &intel_sdvo_connector_funcs,
|
||||
connector_type);
|
||||
drm_connector_helper_add(connector, &intel_sdvo_connector_helper_funcs);
|
||||
connector->interlace_allowed = 0;
|
||||
connector->doublescan_allowed = 0;
|
||||
connector->display_info.subpixel_order = SubPixelHorizontalRGB;
|
||||
|
||||
drm_encoder_init(dev, &intel_output->enc, &intel_sdvo_enc_funcs, encoder_type);
|
||||
drm_encoder_helper_add(&intel_output->enc, &intel_sdvo_helper_funcs);
|
||||
connector->connector_type = connector_type;
|
||||
|
||||
drm_mode_connector_attach_encoder(&intel_output->base, &intel_output->enc);
|
||||
drm_sysfs_connector_add(connector);
|
||||
@ -1829,14 +1921,13 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device)
|
||||
sdvo_priv->caps.output_flags &
|
||||
(SDVO_OUTPUT_TMDS1 | SDVO_OUTPUT_RGB1) ? 'Y' : 'N');
|
||||
|
||||
intel_output->ddc_bus = i2cbus;
|
||||
|
||||
return true;
|
||||
|
||||
err_i2c:
|
||||
if (ddcbus != NULL)
|
||||
intel_i2c_destroy(intel_output->ddc_bus);
|
||||
intel_i2c_destroy(intel_output->i2c_bus);
|
||||
err_connector:
|
||||
drm_connector_cleanup(connector);
|
||||
err_inteloutput:
|
||||
kfree(intel_output);
|
||||
|
||||
return false;
|
||||
|
@ -1519,6 +1519,30 @@ static __inline__ void *drm_calloc(size_t nmemb, size_t size, int area)
|
||||
{
|
||||
return kcalloc(nmemb, size, GFP_KERNEL);
|
||||
}
|
||||
|
||||
static __inline__ void *drm_calloc_large(size_t nmemb, size_t size)
|
||||
{
|
||||
u8 *addr;
|
||||
|
||||
if (size <= PAGE_SIZE)
|
||||
return kcalloc(nmemb, size, GFP_KERNEL);
|
||||
|
||||
addr = vmalloc(nmemb * size);
|
||||
if (!addr)
|
||||
return NULL;
|
||||
|
||||
memset(addr, 0, nmemb * size);
|
||||
|
||||
return addr;
|
||||
}
|
||||
|
||||
static __inline void drm_free_large(void *ptr)
|
||||
{
|
||||
if (!is_vmalloc_addr(ptr))
|
||||
return kfree(ptr);
|
||||
|
||||
vfree(ptr);
|
||||
}
|
||||
#else
|
||||
extern void *drm_alloc(size_t size, int area);
|
||||
extern void drm_free(void *pt, size_t size, int area);
|
||||
|
Loading…
Reference in New Issue
Block a user