Commit 4c44323d authored by Linus Torvalds's avatar Linus Torvalds

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

* 'drm-next' of git://git.kernel.org/pub/scm/linux/kernel/git/airlied/drm-2.6:
  drm/i915: lock correct mutex around object unreference.
  drm/i915: add support for physical memory objects
  drm/i915: make LVDS fixed mode a preferred mode
  drm: handle depth & bpp changes correctly
  drm: initial KMS config fixes
  drm/i915: setup sarea properly in master_priv
  drm/i915: set vblank enabled flag correctly across IRQ install/uninstall
  drm/i915: don't enable vblanks on disabled pipes
parents 50246dd4 34b8686e
...@@ -36,7 +36,7 @@ ...@@ -36,7 +36,7 @@
/* /*
* Detailed mode info for 800x600@60Hz * Detailed mode info for 800x600@60Hz
*/ */
static struct drm_display_mode std_mode[] = { static struct drm_display_mode std_modes[] = {
{ DRM_MODE("800x600", DRM_MODE_TYPE_DEFAULT, 40000, 800, 840, { DRM_MODE("800x600", DRM_MODE_TYPE_DEFAULT, 40000, 800, 840,
968, 1056, 0, 600, 601, 605, 628, 0, 968, 1056, 0, 600, 601, 605, 628, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
...@@ -60,15 +60,18 @@ static struct drm_display_mode std_mode[] = { ...@@ -60,15 +60,18 @@ static struct drm_display_mode std_mode[] = {
* changes have occurred. * changes have occurred.
* *
* FIXME: take into account monitor limits * FIXME: take into account monitor limits
*
* RETURNS:
* Number of modes found on @connector.
*/ */
void drm_helper_probe_single_connector_modes(struct drm_connector *connector, int drm_helper_probe_single_connector_modes(struct drm_connector *connector,
uint32_t maxX, uint32_t maxY) uint32_t maxX, uint32_t maxY)
{ {
struct drm_device *dev = connector->dev; struct drm_device *dev = connector->dev;
struct drm_display_mode *mode, *t; struct drm_display_mode *mode, *t;
struct drm_connector_helper_funcs *connector_funcs = struct drm_connector_helper_funcs *connector_funcs =
connector->helper_private; connector->helper_private;
int ret; int count = 0;
DRM_DEBUG("%s\n", drm_get_connector_name(connector)); DRM_DEBUG("%s\n", drm_get_connector_name(connector));
/* set all modes to the unverified state */ /* set all modes to the unverified state */
...@@ -81,14 +84,14 @@ void drm_helper_probe_single_connector_modes(struct drm_connector *connector, ...@@ -81,14 +84,14 @@ void drm_helper_probe_single_connector_modes(struct drm_connector *connector,
DRM_DEBUG("%s is disconnected\n", DRM_DEBUG("%s is disconnected\n",
drm_get_connector_name(connector)); drm_get_connector_name(connector));
/* TODO set EDID to NULL */ /* TODO set EDID to NULL */
return; return 0;
} }
ret = (*connector_funcs->get_modes)(connector); count = (*connector_funcs->get_modes)(connector);
if (!count)
return 0;
if (ret) {
drm_mode_connector_list_update(connector); drm_mode_connector_list_update(connector);
}
if (maxX && maxY) if (maxX && maxY)
drm_mode_validate_size(dev, &connector->modes, maxX, drm_mode_validate_size(dev, &connector->modes, maxX,
...@@ -102,25 +105,8 @@ void drm_helper_probe_single_connector_modes(struct drm_connector *connector, ...@@ -102,25 +105,8 @@ void drm_helper_probe_single_connector_modes(struct drm_connector *connector,
drm_mode_prune_invalid(dev, &connector->modes, true); drm_mode_prune_invalid(dev, &connector->modes, true);
if (list_empty(&connector->modes)) { if (list_empty(&connector->modes))
struct drm_display_mode *stdmode; return 0;
DRM_DEBUG("No valid modes on %s\n",
drm_get_connector_name(connector));
/* Should we do this here ???
* When no valid EDID modes are available we end up
* here and bailed in the past, now we add a standard
* 640x480@60Hz mode and carry on.
*/
stdmode = drm_mode_duplicate(dev, &std_mode[0]);
drm_mode_probed_add(connector, stdmode);
drm_mode_list_concat(&connector->probed_modes,
&connector->modes);
DRM_DEBUG("Adding standard 640x480 @ 60Hz to %s\n",
drm_get_connector_name(connector));
}
drm_mode_sort(&connector->modes); drm_mode_sort(&connector->modes);
...@@ -131,20 +117,58 @@ void drm_helper_probe_single_connector_modes(struct drm_connector *connector, ...@@ -131,20 +117,58 @@ void drm_helper_probe_single_connector_modes(struct drm_connector *connector,
drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V); drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
drm_mode_debug_printmodeline(mode); drm_mode_debug_printmodeline(mode);
} }
return count;
} }
EXPORT_SYMBOL(drm_helper_probe_single_connector_modes); EXPORT_SYMBOL(drm_helper_probe_single_connector_modes);
void drm_helper_probe_connector_modes(struct drm_device *dev, uint32_t maxX, int drm_helper_probe_connector_modes(struct drm_device *dev, uint32_t maxX,
uint32_t maxY) uint32_t maxY)
{ {
struct drm_connector *connector; struct drm_connector *connector;
int count = 0;
list_for_each_entry(connector, &dev->mode_config.connector_list, head) { list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
drm_helper_probe_single_connector_modes(connector, maxX, maxY); count += drm_helper_probe_single_connector_modes(connector,
maxX, maxY);
} }
return count;
} }
EXPORT_SYMBOL(drm_helper_probe_connector_modes); EXPORT_SYMBOL(drm_helper_probe_connector_modes);
static void drm_helper_add_std_modes(struct drm_device *dev,
struct drm_connector *connector)
{
struct drm_display_mode *mode, *t;
int i;
for (i = 0; i < ARRAY_SIZE(std_modes); i++) {
struct drm_display_mode *stdmode;
/*
* When no valid EDID modes are available we end up
* here and bailed in the past, now we add some standard
* modes and move on.
*/
stdmode = drm_mode_duplicate(dev, &std_modes[i]);
drm_mode_probed_add(connector, stdmode);
drm_mode_list_concat(&connector->probed_modes,
&connector->modes);
DRM_DEBUG("Adding mode %s to %s\n", stdmode->name,
drm_get_connector_name(connector));
}
drm_mode_sort(&connector->modes);
DRM_DEBUG("Added std modes on %s\n", drm_get_connector_name(connector));
list_for_each_entry_safe(mode, t, &connector->modes, head) {
mode->vrefresh = drm_mode_vrefresh(mode);
drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
drm_mode_debug_printmodeline(mode);
}
}
/** /**
* drm_helper_crtc_in_use - check if a given CRTC is in a mode_config * drm_helper_crtc_in_use - check if a given CRTC is in a mode_config
...@@ -237,6 +261,8 @@ static void drm_enable_connectors(struct drm_device *dev, bool *enabled) ...@@ -237,6 +261,8 @@ static void drm_enable_connectors(struct drm_device *dev, bool *enabled)
list_for_each_entry(connector, &dev->mode_config.connector_list, head) { list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
enabled[i] = drm_connector_enabled(connector, true); enabled[i] = drm_connector_enabled(connector, true);
DRM_DEBUG("connector %d enabled? %s\n", connector->base.id,
enabled[i] ? "yes" : "no");
any_enabled |= enabled[i]; any_enabled |= enabled[i];
i++; i++;
} }
...@@ -265,11 +291,17 @@ static bool drm_target_preferred(struct drm_device *dev, ...@@ -265,11 +291,17 @@ static bool drm_target_preferred(struct drm_device *dev,
continue; continue;
} }
DRM_DEBUG("looking for preferred mode on connector %d\n",
connector->base.id);
modes[i] = drm_has_preferred_mode(connector, width, height); modes[i] = drm_has_preferred_mode(connector, width, height);
if (!modes[i]) { /* No preferred modes, pick one off the list */
if (!modes[i] && !list_empty(&connector->modes)) {
list_for_each_entry(modes[i], &connector->modes, head) list_for_each_entry(modes[i], &connector->modes, head)
break; break;
} }
DRM_DEBUG("found mode %s\n", modes[i] ? modes[i]->name :
"none");
i++; i++;
} }
return true; return true;
...@@ -369,6 +401,8 @@ static void drm_setup_crtcs(struct drm_device *dev) ...@@ -369,6 +401,8 @@ static void drm_setup_crtcs(struct drm_device *dev)
int width, height; int width, height;
int i, ret; int i, ret;
DRM_DEBUG("\n");
width = dev->mode_config.max_width; width = dev->mode_config.max_width;
height = dev->mode_config.max_height; height = dev->mode_config.max_height;
...@@ -390,6 +424,8 @@ static void drm_setup_crtcs(struct drm_device *dev) ...@@ -390,6 +424,8 @@ static void drm_setup_crtcs(struct drm_device *dev)
if (!ret) if (!ret)
DRM_ERROR("Unable to find initial modes\n"); DRM_ERROR("Unable to find initial modes\n");
DRM_DEBUG("picking CRTCs for %dx%d config\n", width, height);
drm_pick_crtcs(dev, crtcs, modes, 0, width, height); drm_pick_crtcs(dev, crtcs, modes, 0, width, height);
i = 0; i = 0;
...@@ -403,6 +439,8 @@ static void drm_setup_crtcs(struct drm_device *dev) ...@@ -403,6 +439,8 @@ static void drm_setup_crtcs(struct drm_device *dev)
} }
if (mode && crtc) { if (mode && crtc) {
DRM_DEBUG("desired mode %s set on crtc %d\n",
mode->name, crtc->base.id);
crtc->desired_mode = mode; crtc->desired_mode = mode;
connector->encoder->crtc = crtc; connector->encoder->crtc = crtc;
} else } else
...@@ -442,6 +480,7 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc, ...@@ -442,6 +480,7 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
int saved_x, saved_y; int saved_x, saved_y;
struct drm_encoder *encoder; struct drm_encoder *encoder;
bool ret = true; bool ret = true;
bool depth_changed, bpp_changed;
adjusted_mode = drm_mode_duplicate(dev, mode); adjusted_mode = drm_mode_duplicate(dev, mode);
...@@ -450,6 +489,15 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc, ...@@ -450,6 +489,15 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
if (!crtc->enabled) if (!crtc->enabled)
return true; return true;
if (old_fb && crtc->fb) {
depth_changed = (old_fb->depth != crtc->fb->depth);
bpp_changed = (old_fb->bits_per_pixel !=
crtc->fb->bits_per_pixel);
} else {
depth_changed = true;
bpp_changed = true;
}
saved_mode = crtc->mode; saved_mode = crtc->mode;
saved_x = crtc->x; saved_x = crtc->x;
saved_y = crtc->y; saved_y = crtc->y;
...@@ -462,7 +510,8 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc, ...@@ -462,7 +510,8 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
crtc->y = y; crtc->y = y;
if (drm_mode_equal(&saved_mode, &crtc->mode)) { if (drm_mode_equal(&saved_mode, &crtc->mode)) {
if (saved_x != crtc->x || saved_y != crtc->y) { if (saved_x != crtc->x || saved_y != crtc->y ||
depth_changed || bpp_changed) {
crtc_funcs->mode_set_base(crtc, crtc->x, crtc->y, crtc_funcs->mode_set_base(crtc, crtc->x, crtc->y,
old_fb); old_fb);
goto done; goto done;
...@@ -568,8 +617,8 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) ...@@ -568,8 +617,8 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
struct drm_encoder **save_encoders, *new_encoder; struct drm_encoder **save_encoders, *new_encoder;
struct drm_framebuffer *old_fb; struct drm_framebuffer *old_fb;
bool save_enabled; bool save_enabled;
bool changed = false; bool mode_changed = false;
bool flip_or_move = false; bool fb_changed = false;
struct drm_connector *connector; struct drm_connector *connector;
int count = 0, ro, fail = 0; int count = 0, ro, fail = 0;
struct drm_crtc_helper_funcs *crtc_funcs; struct drm_crtc_helper_funcs *crtc_funcs;
...@@ -597,7 +646,10 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) ...@@ -597,7 +646,10 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
/* save previous config */ /* save previous config */
save_enabled = set->crtc->enabled; save_enabled = set->crtc->enabled;
/* this is meant to be num_connector not num_crtc */ /*
* We do mode_config.num_connectors here since we'll look at the
* CRTC and encoder associated with each connector later.
*/
save_crtcs = kzalloc(dev->mode_config.num_connector * save_crtcs = kzalloc(dev->mode_config.num_connector *
sizeof(struct drm_crtc *), GFP_KERNEL); sizeof(struct drm_crtc *), GFP_KERNEL);
if (!save_crtcs) if (!save_crtcs)
...@@ -613,21 +665,25 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) ...@@ -613,21 +665,25 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
/* We should be able to check here if the fb has the same properties /* We should be able to check here if the fb has the same properties
* 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 its a change not a flip */ /* If we have no fb then treat it as a full mode set */
if (set->crtc->fb == NULL) if (set->crtc->fb == NULL)
changed = true; mode_changed = true;
else if ((set->fb->bits_per_pixel !=
set->crtc->fb->bits_per_pixel) ||
set->fb->depth != set->crtc->fb->depth)
fb_changed = true;
else else
flip_or_move = true; fb_changed = true;
} }
if (set->x != set->crtc->x || set->y != set->crtc->y) if (set->x != set->crtc->x || set->y != set->crtc->y)
flip_or_move = 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\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);
changed = true; mode_changed = true;
} }
/* a) traverse passed in connector list and get encoders for them */ /* a) traverse passed in connector list and get encoders for them */
...@@ -650,7 +706,7 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) ...@@ -650,7 +706,7 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
} }
if (new_encoder != connector->encoder) { if (new_encoder != connector->encoder) {
changed = true; mode_changed = true;
connector->encoder = new_encoder; connector->encoder = new_encoder;
} }
} }
...@@ -677,16 +733,16 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) ...@@ -677,16 +733,16 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
new_crtc = set->crtc; new_crtc = set->crtc;
} }
if (new_crtc != connector->encoder->crtc) { if (new_crtc != connector->encoder->crtc) {
changed = true; mode_changed = true;
connector->encoder->crtc = new_crtc; connector->encoder->crtc = new_crtc;
} }
} }
/* mode_set_base is not a required function */ /* mode_set_base is not a required function */
if (flip_or_move && !crtc_funcs->mode_set_base) if (fb_changed && !crtc_funcs->mode_set_base)
changed = true; mode_changed = true;
if (changed) { if (mode_changed) {
old_fb = set->crtc->fb; old_fb = set->crtc->fb;
set->crtc->fb = set->fb; set->crtc->fb = set->fb;
set->crtc->enabled = (set->mode != NULL); set->crtc->enabled = (set->mode != NULL);
...@@ -705,7 +761,7 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) ...@@ -705,7 +761,7 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
set->crtc->desired_mode = set->mode; set->crtc->desired_mode = set->mode;
} }
drm_helper_disable_unused_functions(dev); drm_helper_disable_unused_functions(dev);
} else if (flip_or_move) { } else if (fb_changed) {
old_fb = set->crtc->fb; old_fb = set->crtc->fb;
if (set->crtc->fb != set->fb) if (set->crtc->fb != set->fb)
set->crtc->fb = set->fb; set->crtc->fb = set->fb;
...@@ -764,10 +820,31 @@ bool drm_helper_plugged_event(struct drm_device *dev) ...@@ -764,10 +820,31 @@ bool drm_helper_plugged_event(struct drm_device *dev)
*/ */
bool drm_helper_initial_config(struct drm_device *dev, bool can_grow) bool drm_helper_initial_config(struct drm_device *dev, bool can_grow)
{ {
int ret = false; struct drm_connector *connector;
int count = 0;
drm_helper_plugged_event(dev); count = drm_helper_probe_connector_modes(dev,
return ret; dev->mode_config.max_width,
dev->mode_config.max_height);
/*
* None of the available connectors had any modes, so add some
* and try to light them up anyway
*/
if (!count) {
DRM_ERROR("connectors have no modes, using standard modes\n");
list_for_each_entry(connector,
&dev->mode_config.connector_list,
head)
drm_helper_add_std_modes(dev, connector);
}
drm_setup_crtcs(dev);
/* alert the driver fb layer */
dev->mode_config.funcs->fb_changed(dev);
return 0;
} }
EXPORT_SYMBOL(drm_helper_initial_config); EXPORT_SYMBOL(drm_helper_initial_config);
......
...@@ -267,7 +267,8 @@ EXPORT_SYMBOL(drm_irq_install); ...@@ -267,7 +267,8 @@ EXPORT_SYMBOL(drm_irq_install);
*/ */
int drm_irq_uninstall(struct drm_device * dev) int drm_irq_uninstall(struct drm_device * dev)
{ {
int irq_enabled; unsigned long irqflags;
int irq_enabled, i;
if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ)) if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ))
return -EINVAL; return -EINVAL;
...@@ -277,6 +278,16 @@ int drm_irq_uninstall(struct drm_device * dev) ...@@ -277,6 +278,16 @@ int drm_irq_uninstall(struct drm_device * dev)
dev->irq_enabled = 0; dev->irq_enabled = 0;
mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->struct_mutex);
/*
* Wake up any waiters so they don't hang.
*/
spin_lock_irqsave(&dev->vbl_lock, irqflags);
for (i = 0; i < dev->num_crtcs; i++) {
DRM_WAKEUP(&dev->vbl_queue[i]);
dev->vblank_enabled[i] = 0;
}
spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
if (!irq_enabled) if (!irq_enabled)
return -EINVAL; return -EINVAL;
...@@ -652,8 +663,9 @@ int drm_wait_vblank(struct drm_device *dev, void *data, ...@@ -652,8 +663,9 @@ int drm_wait_vblank(struct drm_device *dev, void *data,
vblwait->request.sequence, crtc); vblwait->request.sequence, crtc);
dev->last_vblank_wait[crtc] = vblwait->request.sequence; dev->last_vblank_wait[crtc] = vblwait->request.sequence;
DRM_WAIT_ON(ret, dev->vbl_queue[crtc], 3 * DRM_HZ, DRM_WAIT_ON(ret, dev->vbl_queue[crtc], 3 * DRM_HZ,
((drm_vblank_count(dev, crtc) (((drm_vblank_count(dev, crtc) -
- vblwait->request.sequence) <= (1 << 23))); vblwait->request.sequence) <= (1 << 23)) ||
!dev->irq_enabled));
if (ret != -EINTR) { if (ret != -EINTR) {
struct timeval now; struct timeval now;
......
...@@ -177,6 +177,14 @@ static int i915_initialize(struct drm_device * dev, drm_i915_init_t * init) ...@@ -177,6 +177,14 @@ static int i915_initialize(struct drm_device * dev, drm_i915_init_t * init)
drm_i915_private_t *dev_priv = dev->dev_private; drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv; struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv;
master_priv->sarea = drm_getsarea(dev);
if (master_priv->sarea) {
master_priv->sarea_priv = (drm_i915_sarea_t *)
((u8 *)master_priv->sarea->handle + init->sarea_priv_offset);
} else {
DRM_DEBUG("sarea not found assuming DRI2 userspace\n");
}
if (init->ring_size != 0) { if (init->ring_size != 0) {
if (dev_priv->ring.ring_obj != NULL) { if (dev_priv->ring.ring_obj != NULL) {
i915_dma_cleanup(dev); i915_dma_cleanup(dev);
...@@ -1152,6 +1160,8 @@ int i915_driver_unload(struct drm_device *dev) ...@@ -1152,6 +1160,8 @@ int i915_driver_unload(struct drm_device *dev)
if (drm_core_check_feature(dev, DRIVER_MODESET)) { if (drm_core_check_feature(dev, DRIVER_MODESET)) {
intel_modeset_cleanup(dev); intel_modeset_cleanup(dev);
i915_gem_free_all_phys_object(dev);
mutex_lock(&dev->struct_mutex); mutex_lock(&dev->struct_mutex);
i915_gem_cleanup_ringbuffer(dev); i915_gem_cleanup_ringbuffer(dev);
mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->struct_mutex);
......
...@@ -72,6 +72,18 @@ enum pipe { ...@@ -72,6 +72,18 @@ enum pipe {
#define WATCH_INACTIVE 0 #define WATCH_INACTIVE 0
#define WATCH_PWRITE 0 #define WATCH_PWRITE 0
#define I915_GEM_PHYS_CURSOR_0 1
#define I915_GEM_PHYS_CURSOR_1 2
#define I915_GEM_PHYS_OVERLAY_REGS 3
#define I915_MAX_PHYS_OBJECT (I915_GEM_PHYS_OVERLAY_REGS)
struct drm_i915_gem_phys_object {
int id;
struct page **page_list;
drm_dma_handle_t *handle;
struct drm_gem_object *cur_obj;
};
typedef struct _drm_i915_ring_buffer { typedef struct _drm_i915_ring_buffer {
int tail_mask; int tail_mask;
unsigned long Size; unsigned long Size;
...@@ -358,6 +370,9 @@ typedef struct drm_i915_private { ...@@ -358,6 +370,9 @@ typedef struct drm_i915_private {
uint32_t bit_6_swizzle_x; uint32_t bit_6_swizzle_x;
/** Bit 6 swizzling required for Y tiling */ /** Bit 6 swizzling required for Y tiling */
uint32_t bit_6_swizzle_y; uint32_t bit_6_swizzle_y;
/* storage for physical objects */
struct drm_i915_gem_phys_object *phys_objs[I915_MAX_PHYS_OBJECT];
} mm; } mm;
} drm_i915_private_t; } drm_i915_private_t;
...@@ -436,6 +451,9 @@ struct drm_i915_gem_object { ...@@ -436,6 +451,9 @@ struct drm_i915_gem_object {
/** User space pin count and filp owning the pin */ /** User space pin count and filp owning the pin */
uint32_t user_pin_count; uint32_t user_pin_count;
struct drm_file *pin_filp; struct drm_file *pin_filp;
/** for phy allocated objects */
struct drm_i915_gem_phys_object *phys_obj;
}; };
/** /**
...@@ -598,6 +616,11 @@ int i915_gem_do_init(struct drm_device *dev, unsigned long start, ...@@ -598,6 +616,11 @@ int i915_gem_do_init(struct drm_device *dev, unsigned long start,
int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf); int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf);
int i915_gem_object_set_to_gtt_domain(struct drm_gem_object *obj, int i915_gem_object_set_to_gtt_domain(struct drm_gem_object *obj,
int write); int write);
int i915_gem_attach_phys_object(struct drm_device *dev,
struct drm_gem_object *obj, int id);
void i915_gem_detach_phys_object(struct drm_device *dev,
struct drm_gem_object *obj);
void i915_gem_free_all_phys_object(struct drm_device *dev);
/* i915_gem_tiling.c */ /* i915_gem_tiling.c */
void i915_gem_detect_bit_6_swizzle(struct drm_device *dev); void i915_gem_detect_bit_6_swizzle(struct drm_device *dev);
......
...@@ -55,6 +55,9 @@ static int i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, ...@@ -55,6 +55,9 @@ static int i915_gem_object_bind_to_gtt(struct drm_gem_object *obj,
static void i915_gem_object_get_fence_reg(struct drm_gem_object *obj); static void i915_gem_object_get_fence_reg(struct drm_gem_object *obj);
static void i915_gem_clear_fence_reg(struct drm_gem_object *obj); static void i915_gem_clear_fence_reg(struct drm_gem_object *obj);
static int i915_gem_evict_something(struct drm_device *dev); static int i915_gem_evict_something(struct drm_device *dev);
static int i915_gem_phys_pwrite(struct drm_device *dev, struct drm_gem_object *obj,
struct drm_i915_gem_pwrite *args,
struct drm_file *file_priv);
int i915_gem_do_init(struct drm_device *dev, unsigned long start, int i915_gem_do_init(struct drm_device *dev, unsigned long start,
unsigned long end) unsigned long end)
...@@ -386,7 +389,9 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data, ...@@ -386,7 +389,9 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data,
* pread/pwrite currently are reading and writing from the CPU * pread/pwrite currently are reading and writing from the CPU
* perspective, requiring manual detiling by the client. * perspective, requiring manual detiling by the client.
*/ */
if (obj_priv->tiling_mode == I915_TILING_NONE && if (obj_priv->phys_obj)
ret = i915_gem_phys_pwrite(dev, obj, args, file_priv);
else if (obj_priv->tiling_mode == I915_TILING_NONE &&
dev->gtt_total != 0) dev->gtt_total != 0)
ret = i915_gem_gtt_pwrite(dev, obj, args, file_priv); ret = i915_gem_gtt_pwrite(dev, obj, args, file_priv);
else else
...@@ -2858,6 +2863,9 @@ void i915_gem_free_object(struct drm_gem_object *obj) ...@@ -2858,6 +2863,9 @@ void i915_gem_free_object(struct drm_gem_object *obj)
while (obj_priv->pin_count > 0) while (obj_priv->pin_count > 0)
i915_gem_object_unpin(obj); i915_gem_object_unpin(obj);
if (obj_priv->phys_obj)
i915_gem_detach_phys_object(dev, obj);
i915_gem_object_unbind(obj); i915_gem_object_unbind(obj);
list = &obj->map_list; list = &obj->map_list;
...@@ -3293,3 +3301,180 @@ i915_gem_load(struct drm_device *dev) ...@@ -3293,3 +3301,180 @@ i915_gem_load(struct drm_device *dev)
i915_gem_detect_bit_6_swizzle(dev); i915_gem_detect_bit_6_swizzle(dev);
} }
/*
* Create a physically contiguous memory object for this object
* e.g. for cursor + overlay regs
*/
int i915_gem_init_phys_object(struct drm_device *dev,
int id, int size)
{
drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_i915_gem_phys_object *phys_obj;
int ret;
if (dev_priv->mm.phys_objs[id - 1] || !size)
return 0;
phys_obj = drm_calloc(1, sizeof(struct drm_i915_gem_phys_object), DRM_MEM_DRIVER);
if (!phys_obj)
return -ENOMEM;
phys_obj->id = id;
phys_obj->handle = drm_pci_alloc(dev, size, 0, 0xffffffff);
if (!phys_obj->handle) {
ret = -ENOMEM;
goto kfree_obj;
}
#ifdef CONFIG_X86
set_memory_wc((unsigned long)phys_obj->handle->vaddr, phys_obj->handle->size / PAGE_SIZE);
#endif
dev_priv->mm.phys_objs[id - 1] = phys_obj;
return 0;
kfree_obj:
drm_free(phys_obj, sizeof(struct drm_i915_gem_phys_object), DRM_MEM_DRIVER);
return ret;
}
void i915_gem_free_phys_object(struct drm_device *dev, int id)
{
drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_i915_gem_phys_object *phys_obj;
if (!dev_priv->mm.phys_objs[id - 1])
return;
phys_obj = dev_priv->mm.phys_objs[id - 1];
if (phys_obj->cur_obj) {
i915_gem_detach_phys_object(dev, phys_obj->cur_obj);
}
#ifdef CONFIG_X86
set_memory_wb((unsigned long)phys_obj->handle->vaddr, phys_obj->handle->size / PAGE_SIZE);
#endif
drm_pci_free(dev, phys_obj->handle);
kfree(phys_obj);
dev_priv->mm.phys_objs[id - 1] = NULL;
}
void i915_gem_free_all_phys_object(struct drm_device *dev)
{
int i;
for (i = 0; i < I915_MAX_PHYS_OBJECT; i++)
i915_gem_free_phys_object(dev, i);
}
void i915_gem_detach_phys_object(struct drm_device *dev,
struct drm_gem_object *obj)
{
struct drm_i915_gem_object *obj_priv;
int i;
int ret;
int page_count;
obj_priv = obj->driver_private;
if (!obj_priv->phys_obj)
return;
ret = i915_gem_object_get_page_list(obj);
if (ret)
goto out;
page_count = obj->size / PAGE_SIZE;
for (i = 0; i < page_count; i++) {
char *dst = kmap_atomic(obj_priv->page_list[i], KM_USER0);
char *src = obj_priv->phys_obj->handle->vaddr + (i * PAGE_SIZE);
memcpy(dst, src, PAGE_SIZE);
kunmap_atomic(dst, KM_USER0);
}
drm_clflush_pages(obj_priv->page_list, page_count);
drm_agp_chipset_flush(dev);
out:
obj_priv->phys_obj->cur_obj = NULL;
obj_priv->phys_obj = NULL;
}
int
i915_gem_attach_phys_object(struct drm_device *dev,
struct drm_gem_object *obj, int id)
{
drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_i915_gem_object *obj_priv;
int ret = 0;
int page_count;
int i;
if (id > I915_MAX_PHYS_OBJECT)
return -EINVAL;
obj_priv = obj->driver_private;
if (obj_priv->phys_obj) {
if (obj_priv->phys_obj->id == id)
return 0;
i915_gem_detach_phys_object(dev, obj);
}
/* create a new object */
if (!dev_priv->mm.phys_objs[id - 1]) {
ret = i915_gem_init_phys_object(dev, id,
obj->size);
if (ret) {
DRM_ERROR("failed to init phys object %d size: %d\n", id, obj->size);
goto out;
}
}
/* bind to the object */
obj_priv->phys_obj = dev_priv->mm.phys_objs[id - 1];
obj_priv->phys_obj->cur_obj = obj;
ret = i915_gem_object_get_page_list(obj);
if (ret) {
DRM_ERROR("failed to get page list\n");
goto out;
}
page_count = obj->size / PAGE_SIZE;
for (i = 0; i < page_count; i++) {
char *src = kmap_atomic(obj_priv->page_list[i], KM_USER0);
char *dst = obj_priv->phys_obj->handle->vaddr + (i * PAGE_SIZE);
memcpy(dst, src, PAGE_SIZE);
kunmap_atomic(src, KM_USER0);
}
return 0;
out:
return ret;
}
static int
i915_gem_phys_pwrite(struct drm_device *dev, struct drm_gem_object *obj,
struct drm_i915_gem_pwrite *args,
struct drm_file *file_priv)
{
struct drm_i915_gem_object *obj_priv = obj->driver_private;
void *obj_addr;
int ret;
char __user *user_data;
user_data = (char __user *) (uintptr_t) args->data_ptr;
obj_addr = obj_priv->phys_obj->handle->vaddr + args->offset;
DRM_ERROR("obj_addr %p, %lld\n", obj_addr, args->size);
ret = copy_from_user(obj_addr, user_data, args->size);
if (ret)
return -EFAULT;
drm_agp_chipset_flush(dev);
return 0;
}
...@@ -411,6 +411,12 @@ int i915_enable_vblank(struct drm_device *dev, int pipe) ...@@ -411,6 +411,12 @@ int i915_enable_vblank(struct drm_device *dev, int pipe)
{ {
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
unsigned long irqflags; unsigned long irqflags;
int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF;
u32 pipeconf;
pipeconf = I915_READ(pipeconf_reg);
if (!(pipeconf & PIPEACONF_ENABLE))
return -EINVAL;
spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags); spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags);
if (IS_I965G(dev)) if (IS_I965G(dev))
......
...@@ -401,6 +401,8 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, ...@@ -401,6 +401,8 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
I915_WRITE(dspstride, crtc->fb->pitch); I915_WRITE(dspstride, crtc->fb->pitch);
dspcntr = I915_READ(dspcntr_reg); dspcntr = I915_READ(dspcntr_reg);
/* Mask out pixel format bits in case we change it */
dspcntr &= ~DISPPLANE_PIXFORMAT_MASK;
switch (crtc->fb->bits_per_pixel) { switch (crtc->fb->bits_per_pixel) {
case 8: case 8:
dspcntr |= DISPPLANE_8BPP; dspcntr |= DISPPLANE_8BPP;
...@@ -1014,21 +1016,25 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc, ...@@ -1014,21 +1016,25 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,
if (bo->size < width * height * 4) { if (bo->size < width * height * 4) {
DRM_ERROR("buffer is to small\n"); DRM_ERROR("buffer is to small\n");
drm_gem_object_unreference(bo); ret = -ENOMEM;
return -ENOMEM; goto fail;
}
if (dev_priv->cursor_needs_physical) {
addr = dev->agp->base + obj_priv->gtt_offset;
} else {
addr = obj_priv->gtt_offset;
} }
/* we only need to pin inside GTT if cursor is non-phy */
if (!dev_priv->cursor_needs_physical) {
ret = i915_gem_object_pin(bo, PAGE_SIZE); ret = i915_gem_object_pin(bo, PAGE_SIZE);
if (ret) { if (ret) {
DRM_ERROR("failed to pin cursor bo\n"); DRM_ERROR("failed to pin cursor bo\n");
drm_gem_object_unreference(bo); goto fail;
return ret; }
addr = obj_priv->gtt_offset;
} else {
ret = i915_gem_attach_phys_object(dev, bo, (pipe == 0) ? I915_GEM_PHYS_CURSOR_0 : I915_GEM_PHYS_CURSOR_1);
if (ret) {
DRM_ERROR("failed to attach phys object\n");
goto fail;
}
addr = obj_priv->phys_obj->handle->busaddr;
} }
temp = 0; temp = 0;
...@@ -1041,14 +1047,25 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc, ...@@ -1041,14 +1047,25 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,
I915_WRITE(base, addr); I915_WRITE(base, addr);
if (intel_crtc->cursor_bo) { if (intel_crtc->cursor_bo) {
if (dev_priv->cursor_needs_physical) {
if (intel_crtc->cursor_bo != bo)
i915_gem_detach_phys_object(dev, intel_crtc->cursor_bo);
} else
i915_gem_object_unpin(intel_crtc->cursor_bo); i915_gem_object_unpin(intel_crtc->cursor_bo);
mutex_lock(&dev->struct_mutex);
drm_gem_object_unreference(intel_crtc->cursor_bo); drm_gem_object_unreference(intel_crtc->cursor_bo);
mutex_unlock(&dev->struct_mutex);
} }
intel_crtc->cursor_addr = addr; intel_crtc->cursor_addr = addr;
intel_crtc->cursor_bo = bo; intel_crtc->cursor_bo = bo;
return 0; return 0;
fail:
mutex_lock(&dev->struct_mutex);
drm_gem_object_unreference(bo);
mutex_unlock(&dev->struct_mutex);
return ret;
} }
static int intel_crtc_cursor_move(struct drm_crtc *crtc, int x, int y) static int intel_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
......
...@@ -456,6 +456,13 @@ void intel_lvds_init(struct drm_device *dev) ...@@ -456,6 +456,13 @@ void intel_lvds_init(struct drm_device *dev)
dev_priv->panel_fixed_mode = dev_priv->panel_fixed_mode =
drm_mode_duplicate(dev, dev_priv->vbt_mode); drm_mode_duplicate(dev, dev_priv->vbt_mode);
mutex_unlock(&dev->mode_config.mutex); mutex_unlock(&dev->mode_config.mutex);
if (dev_priv->panel_fixed_mode) {
dev_priv->panel_fixed_mode->type |=
DRM_MODE_TYPE_PREFERRED;
drm_mode_probed_add(connector,
dev_priv->panel_fixed_mode);
goto out;
}
} }
/* /*
......
...@@ -395,7 +395,7 @@ struct drm_connector_funcs { ...@@ -395,7 +395,7 @@ struct drm_connector_funcs {
void (*save)(struct drm_connector *connector); void (*save)(struct drm_connector *connector);
void (*restore)(struct drm_connector *connector); void (*restore)(struct drm_connector *connector);
enum drm_connector_status (*detect)(struct drm_connector *connector); enum drm_connector_status (*detect)(struct drm_connector *connector);
void (*fill_modes)(struct drm_connector *connector, uint32_t max_width, uint32_t max_height); int (*fill_modes)(struct drm_connector *connector, uint32_t max_width, uint32_t max_height);
int (*set_property)(struct drm_connector *connector, struct drm_property *property, int (*set_property)(struct drm_connector *connector, struct drm_property *property,
uint64_t val); uint64_t val);
void (*destroy)(struct drm_connector *connector); void (*destroy)(struct drm_connector *connector);
......
...@@ -88,7 +88,7 @@ struct drm_connector_helper_funcs { ...@@ -88,7 +88,7 @@ struct drm_connector_helper_funcs {
struct drm_encoder *(*best_encoder)(struct drm_connector *connector); struct drm_encoder *(*best_encoder)(struct drm_connector *connector);
}; };
extern void drm_helper_probe_single_connector_modes(struct drm_connector *connector, uint32_t maxX, uint32_t maxY); extern int drm_helper_probe_single_connector_modes(struct drm_connector *connector, uint32_t maxX, uint32_t maxY);
extern void drm_helper_disable_unused_functions(struct drm_device *dev); extern void drm_helper_disable_unused_functions(struct drm_device *dev);
extern int drm_helper_hotplug_stage_two(struct drm_device *dev); extern int drm_helper_hotplug_stage_two(struct drm_device *dev);
extern bool drm_helper_initial_config(struct drm_device *dev, bool can_grow); extern bool drm_helper_initial_config(struct drm_device *dev, bool can_grow);
......
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