Commit c15d8a64 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'drm-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/airlied/drm-2.6

* 'drm-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/airlied/drm-2.6:
  drm/i915: convert DRM_ERROR to DRM_DEBUG in phys object pwrite path
  drm/i915: make hw page ioremap use ioremap_wc
  drm: edid revision 0 is valid
  drm: Correct unbalanced drm_vblank_put() during mode setting.
  drm: disable encoders before re-routing them
  drm: Fix ordering of bit fields in EDID structure leading huge vsync values.
  drm: Fix shifts of EDID vsync offset/width fields.
  drm/i915: handle bogus VBT panel timing
  drm/i915: remove PLL debugging messages
parents 49021355 e08fb4f6
...@@ -452,6 +452,59 @@ static void drm_setup_crtcs(struct drm_device *dev) ...@@ -452,6 +452,59 @@ static void drm_setup_crtcs(struct drm_device *dev)
kfree(modes); kfree(modes);
kfree(enabled); kfree(enabled);
} }
/**
* drm_encoder_crtc_ok - can a given crtc drive a given encoder?
* @encoder: encoder to test
* @crtc: crtc to test
*
* Return false if @encoder can't be driven by @crtc, true otherwise.
*/
static bool drm_encoder_crtc_ok(struct drm_encoder *encoder,
struct drm_crtc *crtc)
{
struct drm_device *dev;
struct drm_crtc *tmp;
int crtc_mask = 1;
WARN(!crtc, "checking null crtc?");
dev = crtc->dev;
list_for_each_entry(tmp, &dev->mode_config.crtc_list, head) {
if (tmp == crtc)
break;
crtc_mask <<= 1;
}
if (encoder->possible_crtcs & crtc_mask)
return true;
return false;
}
/*
* Check the CRTC we're going to map each output to vs. its current
* CRTC. If they don't match, we have to disable the output and the CRTC
* since the driver will have to re-route things.
*/
static void
drm_crtc_prepare_encoders(struct drm_device *dev)
{
struct drm_encoder_helper_funcs *encoder_funcs;
struct drm_encoder *encoder;
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
encoder_funcs = encoder->helper_private;
/* Disable unused encoders */
if (encoder->crtc == NULL)
(*encoder_funcs->dpms)(encoder, DRM_MODE_DPMS_OFF);
/* Disable encoders whose CRTC is about to change */
if (encoder_funcs->get_crtc &&
encoder->crtc != (*encoder_funcs->get_crtc)(encoder))
(*encoder_funcs->dpms)(encoder, DRM_MODE_DPMS_OFF);
}
}
/** /**
* drm_crtc_set_mode - set a mode * drm_crtc_set_mode - set a mode
* @crtc: CRTC to program * @crtc: CRTC to program
...@@ -547,6 +600,8 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc, ...@@ -547,6 +600,8 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
encoder_funcs->prepare(encoder); encoder_funcs->prepare(encoder);
} }
drm_crtc_prepare_encoders(dev);
crtc_funcs->prepare(crtc); crtc_funcs->prepare(crtc);
/* Set up the DPLL and any encoders state that needs to adjust or depend /* Set up the DPLL and any encoders state that needs to adjust or depend
...@@ -617,7 +672,7 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) ...@@ -617,7 +672,7 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
struct drm_device *dev; struct drm_device *dev;
struct drm_crtc **save_crtcs, *new_crtc; struct drm_crtc **save_crtcs, *new_crtc;
struct drm_encoder **save_encoders, *new_encoder; struct drm_encoder **save_encoders, *new_encoder;
struct drm_framebuffer *old_fb; struct drm_framebuffer *old_fb = NULL;
bool save_enabled; bool save_enabled;
bool mode_changed = false; bool mode_changed = false;
bool fb_changed = false; bool fb_changed = false;
...@@ -668,9 +723,10 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) ...@@ -668,9 +723,10 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
* and then just flip_or_move it */ * and then just flip_or_move it */
if (set->crtc->fb != set->fb) { if (set->crtc->fb != set->fb) {
/* If we have no fb then treat it as a full mode set */ /* If we have no fb then treat it as a full mode set */
if (set->crtc->fb == NULL) if (set->crtc->fb == NULL) {
DRM_DEBUG("crtc has no fb, full mode set\n");
mode_changed = true; mode_changed = true;
else if ((set->fb->bits_per_pixel != } else if ((set->fb->bits_per_pixel !=
set->crtc->fb->bits_per_pixel) || set->crtc->fb->bits_per_pixel) ||
set->fb->depth != set->crtc->fb->depth) set->fb->depth != set->crtc->fb->depth)
fb_changed = true; fb_changed = true;
...@@ -682,7 +738,7 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) ...@@ -682,7 +738,7 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
fb_changed = true; fb_changed = true;
if (set->mode && !drm_mode_equal(set->mode, &set->crtc->mode)) { if (set->mode && !drm_mode_equal(set->mode, &set->crtc->mode)) {
DRM_DEBUG("modes are different\n"); DRM_DEBUG("modes are different, full mode set\n");
drm_mode_debug_printmodeline(&set->crtc->mode); drm_mode_debug_printmodeline(&set->crtc->mode);
drm_mode_debug_printmodeline(set->mode); drm_mode_debug_printmodeline(set->mode);
mode_changed = true; mode_changed = true;
...@@ -708,6 +764,7 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) ...@@ -708,6 +764,7 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
} }
if (new_encoder != connector->encoder) { if (new_encoder != connector->encoder) {
DRM_DEBUG("encoder changed, full mode switch\n");
mode_changed = true; mode_changed = true;
connector->encoder = new_encoder; connector->encoder = new_encoder;
} }
...@@ -734,10 +791,20 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) ...@@ -734,10 +791,20 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
if (set->connectors[ro] == connector) if (set->connectors[ro] == connector)
new_crtc = set->crtc; new_crtc = set->crtc;
} }
/* Make sure the new CRTC will work with the encoder */
if (new_crtc &&
!drm_encoder_crtc_ok(connector->encoder, new_crtc)) {
ret = -EINVAL;
goto fail_set_mode;
}
if (new_crtc != connector->encoder->crtc) { if (new_crtc != connector->encoder->crtc) {
DRM_DEBUG("crtc changed, full mode switch\n");
mode_changed = true; mode_changed = true;
connector->encoder->crtc = new_crtc; connector->encoder->crtc = new_crtc;
} }
DRM_DEBUG("setting connector %d crtc to %p\n",
connector->base.id, new_crtc);
} }
/* mode_set_base is not a required function */ /* mode_set_base is not a required function */
...@@ -781,6 +848,7 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) ...@@ -781,6 +848,7 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
fail_set_mode: fail_set_mode:
set->crtc->enabled = save_enabled; set->crtc->enabled = save_enabled;
set->crtc->fb = old_fb;
count = 0; count = 0;
list_for_each_entry(connector, &dev->mode_config.connector_list, head) { list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
if (!connector->encoder) if (!connector->encoder)
......
...@@ -125,7 +125,7 @@ static bool edid_is_valid(struct edid *edid) ...@@ -125,7 +125,7 @@ static bool edid_is_valid(struct edid *edid)
DRM_ERROR("EDID has major version %d, instead of 1\n", edid->version); DRM_ERROR("EDID has major version %d, instead of 1\n", edid->version);
goto bad; goto bad;
} }
if (edid->revision <= 0 || edid->revision > 3) { if (edid->revision > 3) {
DRM_ERROR("EDID has minor version %d, which is not between 0-3\n", edid->revision); DRM_ERROR("EDID has minor version %d, which is not between 0-3\n", edid->revision);
goto bad; goto bad;
} }
...@@ -320,10 +320,10 @@ static struct drm_display_mode *drm_mode_detailed(struct drm_device *dev, ...@@ -320,10 +320,10 @@ static struct drm_display_mode *drm_mode_detailed(struct drm_device *dev,
mode->htotal = mode->hdisplay + ((pt->hblank_hi << 8) | pt->hblank_lo); mode->htotal = mode->hdisplay + ((pt->hblank_hi << 8) | pt->hblank_lo);
mode->vdisplay = (pt->vactive_hi << 8) | pt->vactive_lo; mode->vdisplay = (pt->vactive_hi << 8) | pt->vactive_lo;
mode->vsync_start = mode->vdisplay + ((pt->vsync_offset_hi << 8) | mode->vsync_start = mode->vdisplay + ((pt->vsync_offset_hi << 4) |
pt->vsync_offset_lo); pt->vsync_offset_lo);
mode->vsync_end = mode->vsync_start + mode->vsync_end = mode->vsync_start +
((pt->vsync_pulse_width_hi << 8) | ((pt->vsync_pulse_width_hi << 4) |
pt->vsync_pulse_width_lo); pt->vsync_pulse_width_lo);
mode->vtotal = mode->vdisplay + ((pt->vblank_hi << 8) | pt->vblank_lo); mode->vtotal = mode->vdisplay + ((pt->vblank_hi << 8) | pt->vblank_lo);
......
...@@ -435,6 +435,8 @@ EXPORT_SYMBOL(drm_vblank_get); ...@@ -435,6 +435,8 @@ EXPORT_SYMBOL(drm_vblank_get);
*/ */
void drm_vblank_put(struct drm_device *dev, int crtc) void drm_vblank_put(struct drm_device *dev, int crtc)
{ {
BUG_ON (atomic_read (&dev->vblank_refcount[crtc]) == 0);
/* Last user schedules interrupt disable */ /* Last user schedules interrupt disable */
if (atomic_dec_and_test(&dev->vblank_refcount[crtc])) if (atomic_dec_and_test(&dev->vblank_refcount[crtc]))
mod_timer(&dev->vblank_disable_timer, jiffies + 5*DRM_HZ); mod_timer(&dev->vblank_disable_timer, jiffies + 5*DRM_HZ);
...@@ -460,8 +462,9 @@ void drm_vblank_pre_modeset(struct drm_device *dev, int crtc) ...@@ -460,8 +462,9 @@ void drm_vblank_pre_modeset(struct drm_device *dev, int crtc)
* so that interrupts remain enabled in the interim. * so that interrupts remain enabled in the interim.
*/ */
if (!dev->vblank_inmodeset[crtc]) { if (!dev->vblank_inmodeset[crtc]) {
dev->vblank_inmodeset[crtc] = 1; dev->vblank_inmodeset[crtc] = 0x1;
drm_vblank_get(dev, crtc); if (drm_vblank_get(dev, crtc) == 0)
dev->vblank_inmodeset[crtc] |= 0x2;
} }
} }
EXPORT_SYMBOL(drm_vblank_pre_modeset); EXPORT_SYMBOL(drm_vblank_pre_modeset);
...@@ -473,9 +476,12 @@ void drm_vblank_post_modeset(struct drm_device *dev, int crtc) ...@@ -473,9 +476,12 @@ void drm_vblank_post_modeset(struct drm_device *dev, int crtc)
if (dev->vblank_inmodeset[crtc]) { if (dev->vblank_inmodeset[crtc]) {
spin_lock_irqsave(&dev->vbl_lock, irqflags); spin_lock_irqsave(&dev->vbl_lock, irqflags);
dev->vblank_disable_allowed = 1; dev->vblank_disable_allowed = 1;
dev->vblank_inmodeset[crtc] = 0;
spin_unlock_irqrestore(&dev->vbl_lock, irqflags); spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
drm_vblank_put(dev, crtc);
if (dev->vblank_inmodeset[crtc] & 0x2)
drm_vblank_put(dev, crtc);
dev->vblank_inmodeset[crtc] = 0;
} }
} }
EXPORT_SYMBOL(drm_vblank_post_modeset); EXPORT_SYMBOL(drm_vblank_post_modeset);
......
...@@ -811,7 +811,7 @@ static int i915_set_status_page(struct drm_device *dev, void *data, ...@@ -811,7 +811,7 @@ static int i915_set_status_page(struct drm_device *dev, void *data,
dev_priv->hws_map.flags = 0; dev_priv->hws_map.flags = 0;
dev_priv->hws_map.mtrr = 0; dev_priv->hws_map.mtrr = 0;
drm_core_ioremap(&dev_priv->hws_map, dev); drm_core_ioremap_wc(&dev_priv->hws_map, dev);
if (dev_priv->hws_map.handle == NULL) { if (dev_priv->hws_map.handle == NULL) {
i915_dma_cleanup(dev); i915_dma_cleanup(dev);
dev_priv->status_gfx_addr = 0; dev_priv->status_gfx_addr = 0;
......
...@@ -3548,7 +3548,7 @@ i915_gem_phys_pwrite(struct drm_device *dev, struct drm_gem_object *obj, ...@@ -3548,7 +3548,7 @@ i915_gem_phys_pwrite(struct drm_device *dev, struct drm_gem_object *obj,
user_data = (char __user *) (uintptr_t) args->data_ptr; user_data = (char __user *) (uintptr_t) args->data_ptr;
obj_addr = obj_priv->phys_obj->handle->vaddr + args->offset; obj_addr = obj_priv->phys_obj->handle->vaddr + args->offset;
DRM_ERROR("obj_addr %p, %lld\n", obj_addr, args->size); DRM_DEBUG("obj_addr %p, %lld\n", obj_addr, args->size);
ret = copy_from_user(obj_addr, user_data, args->size); ret = copy_from_user(obj_addr, user_data, args->size);
if (ret) if (ret)
return -EFAULT; return -EFAULT;
......
...@@ -111,6 +111,12 @@ parse_panel_data(struct drm_i915_private *dev_priv, struct bdb_header *bdb) ...@@ -111,6 +111,12 @@ parse_panel_data(struct drm_i915_private *dev_priv, struct bdb_header *bdb)
panel_fixed_mode->clock = dvo_timing->clock * 10; panel_fixed_mode->clock = dvo_timing->clock * 10;
panel_fixed_mode->type = DRM_MODE_TYPE_PREFERRED; 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); drm_mode_set_name(panel_fixed_mode);
dev_priv->vbt_mode = panel_fixed_mode; dev_priv->vbt_mode = panel_fixed_mode;
......
...@@ -217,7 +217,7 @@ bool intel_pipe_has_type (struct drm_crtc *crtc, int type) ...@@ -217,7 +217,7 @@ bool intel_pipe_has_type (struct drm_crtc *crtc, int type)
return false; return false;
} }
#define INTELPllInvalid(s) do { DRM_DEBUG(s); return false; } while (0) #define INTELPllInvalid(s) do { /* DRM_DEBUG(s); */ return false; } while (0)
/** /**
* Returns whether the given set of divisors are valid for a given refclk with * Returns whether the given set of divisors are valid for a given refclk with
* the given connectors. * the given connectors.
......
...@@ -76,6 +76,7 @@ struct drm_encoder_helper_funcs { ...@@ -76,6 +76,7 @@ struct drm_encoder_helper_funcs {
void (*mode_set)(struct drm_encoder *encoder, void (*mode_set)(struct drm_encoder *encoder,
struct drm_display_mode *mode, struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode); struct drm_display_mode *adjusted_mode);
struct drm_crtc *(*get_crtc)(struct drm_encoder *encoder);
/* detect for DAC style encoders */ /* detect for DAC style encoders */
enum drm_connector_status (*detect)(struct drm_encoder *encoder, enum drm_connector_status (*detect)(struct drm_encoder *encoder,
struct drm_connector *connector); struct drm_connector *connector);
......
...@@ -58,10 +58,10 @@ struct detailed_pixel_timing { ...@@ -58,10 +58,10 @@ struct detailed_pixel_timing {
u8 hsync_pulse_width_lo; u8 hsync_pulse_width_lo;
u8 vsync_pulse_width_lo:4; u8 vsync_pulse_width_lo:4;
u8 vsync_offset_lo:4; u8 vsync_offset_lo:4;
u8 hsync_pulse_width_hi:2;
u8 hsync_offset_hi:2;
u8 vsync_pulse_width_hi:2; u8 vsync_pulse_width_hi:2;
u8 vsync_offset_hi:2; u8 vsync_offset_hi:2;
u8 hsync_pulse_width_hi:2;
u8 hsync_offset_hi:2;
u8 width_mm_lo; u8 width_mm_lo;
u8 height_mm_lo; u8 height_mm_lo;
u8 height_mm_hi:4; u8 height_mm_hi:4;
......
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