mirror of
https://github.com/torvalds/linux.git
synced 2024-11-16 17:12:06 +00:00
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
This commit is contained in:
commit
4c44323db1
@ -36,7 +36,7 @@
|
||||
/*
|
||||
* 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,
|
||||
968, 1056, 0, 600, 601, 605, 628, 0,
|
||||
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
|
||||
@ -60,15 +60,18 @@ static struct drm_display_mode std_mode[] = {
|
||||
* changes have occurred.
|
||||
*
|
||||
* FIXME: take into account monitor limits
|
||||
*
|
||||
* RETURNS:
|
||||
* Number of modes found on @connector.
|
||||
*/
|
||||
void drm_helper_probe_single_connector_modes(struct drm_connector *connector,
|
||||
uint32_t maxX, uint32_t maxY)
|
||||
int drm_helper_probe_single_connector_modes(struct drm_connector *connector,
|
||||
uint32_t maxX, uint32_t maxY)
|
||||
{
|
||||
struct drm_device *dev = connector->dev;
|
||||
struct drm_display_mode *mode, *t;
|
||||
struct drm_connector_helper_funcs *connector_funcs =
|
||||
connector->helper_private;
|
||||
int ret;
|
||||
int count = 0;
|
||||
|
||||
DRM_DEBUG("%s\n", drm_get_connector_name(connector));
|
||||
/* set all modes to the unverified state */
|
||||
@ -81,14 +84,14 @@ void drm_helper_probe_single_connector_modes(struct drm_connector *connector,
|
||||
DRM_DEBUG("%s is disconnected\n",
|
||||
drm_get_connector_name(connector));
|
||||
/* 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)
|
||||
drm_mode_validate_size(dev, &connector->modes, maxX,
|
||||
@ -102,25 +105,8 @@ void drm_helper_probe_single_connector_modes(struct drm_connector *connector,
|
||||
|
||||
drm_mode_prune_invalid(dev, &connector->modes, true);
|
||||
|
||||
if (list_empty(&connector->modes)) {
|
||||
struct drm_display_mode *stdmode;
|
||||
|
||||
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));
|
||||
}
|
||||
if (list_empty(&connector->modes))
|
||||
return 0;
|
||||
|
||||
drm_mode_sort(&connector->modes);
|
||||
|
||||
@ -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_debug_printmodeline(mode);
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
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)
|
||||
{
|
||||
struct drm_connector *connector;
|
||||
int count = 0;
|
||||
|
||||
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);
|
||||
|
||||
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
|
||||
@ -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) {
|
||||
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];
|
||||
i++;
|
||||
}
|
||||
@ -265,11 +291,17 @@ static bool drm_target_preferred(struct drm_device *dev,
|
||||
continue;
|
||||
}
|
||||
|
||||
DRM_DEBUG("looking for preferred mode on connector %d\n",
|
||||
connector->base.id);
|
||||
|
||||
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)
|
||||
break;
|
||||
}
|
||||
DRM_DEBUG("found mode %s\n", modes[i] ? modes[i]->name :
|
||||
"none");
|
||||
i++;
|
||||
}
|
||||
return true;
|
||||
@ -369,6 +401,8 @@ static void drm_setup_crtcs(struct drm_device *dev)
|
||||
int width, height;
|
||||
int i, ret;
|
||||
|
||||
DRM_DEBUG("\n");
|
||||
|
||||
width = dev->mode_config.max_width;
|
||||
height = dev->mode_config.max_height;
|
||||
|
||||
@ -390,6 +424,8 @@ static void drm_setup_crtcs(struct drm_device *dev)
|
||||
if (!ret)
|
||||
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);
|
||||
|
||||
i = 0;
|
||||
@ -403,6 +439,8 @@ static void drm_setup_crtcs(struct drm_device *dev)
|
||||
}
|
||||
|
||||
if (mode && crtc) {
|
||||
DRM_DEBUG("desired mode %s set on crtc %d\n",
|
||||
mode->name, crtc->base.id);
|
||||
crtc->desired_mode = mode;
|
||||
connector->encoder->crtc = crtc;
|
||||
} else
|
||||
@ -442,6 +480,7 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
|
||||
int saved_x, saved_y;
|
||||
struct drm_encoder *encoder;
|
||||
bool ret = true;
|
||||
bool depth_changed, bpp_changed;
|
||||
|
||||
adjusted_mode = drm_mode_duplicate(dev, mode);
|
||||
|
||||
@ -450,6 +489,15 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
|
||||
if (!crtc->enabled)
|
||||
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_x = crtc->x;
|
||||
saved_y = crtc->y;
|
||||
@ -462,7 +510,8 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
|
||||
crtc->y = y;
|
||||
|
||||
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,
|
||||
old_fb);
|
||||
goto done;
|
||||
@ -568,8 +617,8 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
|
||||
struct drm_encoder **save_encoders, *new_encoder;
|
||||
struct drm_framebuffer *old_fb;
|
||||
bool save_enabled;
|
||||
bool changed = false;
|
||||
bool flip_or_move = false;
|
||||
bool mode_changed = false;
|
||||
bool fb_changed = false;
|
||||
struct drm_connector *connector;
|
||||
int count = 0, ro, fail = 0;
|
||||
struct drm_crtc_helper_funcs *crtc_funcs;
|
||||
@ -597,7 +646,10 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
|
||||
/* save previous config */
|
||||
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 *
|
||||
sizeof(struct drm_crtc *), GFP_KERNEL);
|
||||
if (!save_crtcs)
|
||||
@ -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
|
||||
* and then just flip_or_move it */
|
||||
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)
|
||||
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
|
||||
flip_or_move = true;
|
||||
fb_changed = true;
|
||||
}
|
||||
|
||||
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)) {
|
||||
DRM_DEBUG("modes are different\n");
|
||||
drm_mode_debug_printmodeline(&set->crtc->mode);
|
||||
drm_mode_debug_printmodeline(set->mode);
|
||||
changed = true;
|
||||
mode_changed = true;
|
||||
}
|
||||
|
||||
/* 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)
|
||||
}
|
||||
|
||||
if (new_encoder != connector->encoder) {
|
||||
changed = true;
|
||||
mode_changed = true;
|
||||
connector->encoder = new_encoder;
|
||||
}
|
||||
}
|
||||
@ -677,16 +733,16 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
|
||||
new_crtc = set->crtc;
|
||||
}
|
||||
if (new_crtc != connector->encoder->crtc) {
|
||||
changed = true;
|
||||
mode_changed = true;
|
||||
connector->encoder->crtc = new_crtc;
|
||||
}
|
||||
}
|
||||
|
||||
/* mode_set_base is not a required function */
|
||||
if (flip_or_move && !crtc_funcs->mode_set_base)
|
||||
changed = true;
|
||||
if (fb_changed && !crtc_funcs->mode_set_base)
|
||||
mode_changed = true;
|
||||
|
||||
if (changed) {
|
||||
if (mode_changed) {
|
||||
old_fb = set->crtc->fb;
|
||||
set->crtc->fb = set->fb;
|
||||
set->crtc->enabled = (set->mode != NULL);
|
||||
@ -705,7 +761,7 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
|
||||
set->crtc->desired_mode = set->mode;
|
||||
}
|
||||
drm_helper_disable_unused_functions(dev);
|
||||
} else if (flip_or_move) {
|
||||
} else if (fb_changed) {
|
||||
old_fb = set->crtc->fb;
|
||||
if (set->crtc->fb != set->fb)
|
||||
set->crtc->fb = set->fb;
|
||||
@ -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)
|
||||
{
|
||||
int ret = false;
|
||||
struct drm_connector *connector;
|
||||
int count = 0;
|
||||
|
||||
drm_helper_plugged_event(dev);
|
||||
return ret;
|
||||
count = drm_helper_probe_connector_modes(dev,
|
||||
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);
|
||||
|
||||
|
@ -267,7 +267,8 @@ EXPORT_SYMBOL(drm_irq_install);
|
||||
*/
|
||||
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))
|
||||
return -EINVAL;
|
||||
@ -277,6 +278,16 @@ int drm_irq_uninstall(struct drm_device * dev)
|
||||
dev->irq_enabled = 0;
|
||||
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)
|
||||
return -EINVAL;
|
||||
|
||||
@ -652,8 +663,9 @@ int drm_wait_vblank(struct drm_device *dev, void *data,
|
||||
vblwait->request.sequence, crtc);
|
||||
dev->last_vblank_wait[crtc] = vblwait->request.sequence;
|
||||
DRM_WAIT_ON(ret, dev->vbl_queue[crtc], 3 * DRM_HZ,
|
||||
((drm_vblank_count(dev, crtc)
|
||||
- vblwait->request.sequence) <= (1 << 23)));
|
||||
(((drm_vblank_count(dev, crtc) -
|
||||
vblwait->request.sequence) <= (1 << 23)) ||
|
||||
!dev->irq_enabled));
|
||||
|
||||
if (ret != -EINTR) {
|
||||
struct timeval now;
|
||||
|
@ -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;
|
||||
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 (dev_priv->ring.ring_obj != NULL) {
|
||||
i915_dma_cleanup(dev);
|
||||
@ -1152,6 +1160,8 @@ int i915_driver_unload(struct drm_device *dev)
|
||||
if (drm_core_check_feature(dev, DRIVER_MODESET)) {
|
||||
intel_modeset_cleanup(dev);
|
||||
|
||||
i915_gem_free_all_phys_object(dev);
|
||||
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
i915_gem_cleanup_ringbuffer(dev);
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
|
@ -72,6 +72,18 @@ enum pipe {
|
||||
#define WATCH_INACTIVE 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 {
|
||||
int tail_mask;
|
||||
unsigned long Size;
|
||||
@ -358,6 +370,9 @@ typedef struct drm_i915_private {
|
||||
uint32_t bit_6_swizzle_x;
|
||||
/** Bit 6 swizzling required for Y tiling */
|
||||
uint32_t bit_6_swizzle_y;
|
||||
|
||||
/* storage for physical objects */
|
||||
struct drm_i915_gem_phys_object *phys_objs[I915_MAX_PHYS_OBJECT];
|
||||
} mm;
|
||||
} drm_i915_private_t;
|
||||
|
||||
@ -436,6 +451,9 @@ struct drm_i915_gem_object {
|
||||
/** User space pin count and filp owning the pin */
|
||||
uint32_t user_pin_count;
|
||||
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,
|
||||
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 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 */
|
||||
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,
|
||||
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 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,
|
||||
unsigned long end)
|
||||
@ -386,8 +389,10 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data,
|
||||
* pread/pwrite currently are reading and writing from the CPU
|
||||
* perspective, requiring manual detiling by the client.
|
||||
*/
|
||||
if (obj_priv->tiling_mode == I915_TILING_NONE &&
|
||||
dev->gtt_total != 0)
|
||||
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)
|
||||
ret = i915_gem_gtt_pwrite(dev, obj, args, file_priv);
|
||||
else
|
||||
ret = i915_gem_shmem_pwrite(dev, obj, args, file_priv);
|
||||
@ -2858,6 +2863,9 @@ void i915_gem_free_object(struct drm_gem_object *obj)
|
||||
while (obj_priv->pin_count > 0)
|
||||
i915_gem_object_unpin(obj);
|
||||
|
||||
if (obj_priv->phys_obj)
|
||||
i915_gem_detach_phys_object(dev, obj);
|
||||
|
||||
i915_gem_object_unbind(obj);
|
||||
|
||||
list = &obj->map_list;
|
||||
@ -3293,3 +3301,180 @@ i915_gem_load(struct drm_device *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)
|
||||
{
|
||||
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
|
||||
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);
|
||||
if (IS_I965G(dev))
|
||||
|
@ -401,6 +401,8 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
|
||||
I915_WRITE(dspstride, crtc->fb->pitch);
|
||||
|
||||
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) {
|
||||
case 8:
|
||||
dspcntr |= DISPPLANE_8BPP;
|
||||
@ -1014,21 +1016,25 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,
|
||||
|
||||
if (bo->size < width * height * 4) {
|
||||
DRM_ERROR("buffer is to small\n");
|
||||
drm_gem_object_unreference(bo);
|
||||
return -ENOMEM;
|
||||
ret = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (dev_priv->cursor_needs_physical) {
|
||||
addr = dev->agp->base + obj_priv->gtt_offset;
|
||||
} else {
|
||||
/* 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);
|
||||
if (ret) {
|
||||
DRM_ERROR("failed to pin cursor bo\n");
|
||||
goto fail;
|
||||
}
|
||||
addr = obj_priv->gtt_offset;
|
||||
}
|
||||
|
||||
ret = i915_gem_object_pin(bo, PAGE_SIZE);
|
||||
if (ret) {
|
||||
DRM_ERROR("failed to pin cursor bo\n");
|
||||
drm_gem_object_unreference(bo);
|
||||
return ret;
|
||||
} 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;
|
||||
@ -1041,14 +1047,25 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,
|
||||
I915_WRITE(base, addr);
|
||||
|
||||
if (intel_crtc->cursor_bo) {
|
||||
i915_gem_object_unpin(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);
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
drm_gem_object_unreference(intel_crtc->cursor_bo);
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
}
|
||||
|
||||
intel_crtc->cursor_addr = addr;
|
||||
intel_crtc->cursor_bo = bo;
|
||||
|
||||
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)
|
||||
|
@ -456,6 +456,13 @@ void intel_lvds_init(struct drm_device *dev)
|
||||
dev_priv->panel_fixed_mode =
|
||||
drm_mode_duplicate(dev, dev_priv->vbt_mode);
|
||||
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 {
|
||||
void (*save)(struct drm_connector *connector);
|
||||
void (*restore)(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,
|
||||
uint64_t val);
|
||||
void (*destroy)(struct drm_connector *connector);
|
||||
|
@ -88,7 +88,7 @@ struct drm_connector_helper_funcs {
|
||||
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 int drm_helper_hotplug_stage_two(struct drm_device *dev);
|
||||
extern bool drm_helper_initial_config(struct drm_device *dev, bool can_grow);
|
||||
|
Loading…
Reference in New Issue
Block a user