Skip to content

Commit

Permalink
Merge branch 'drm-next' of git://git.kernel.org/pub/scm/linux/kernel/…
Browse files Browse the repository at this point in the history
…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
  • Loading branch information
Linus Torvalds committed Jan 16, 2009
2 parents 50246dd + 34b8686 commit 4c44323
Show file tree
Hide file tree
Showing 10 changed files with 406 additions and 69 deletions.
175 changes: 126 additions & 49 deletions drivers/gpu/drm/drm_crtc_helper.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) },
Expand All @@ -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 */
Expand All @@ -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,
Expand All @@ -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);

Expand All @@ -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
Expand Down Expand Up @@ -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++;
}
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;

Expand All @@ -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;
Expand All @@ -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
Expand Down Expand Up @@ -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);

Expand All @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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)
Expand All @@ -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 */
Expand All @@ -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;
}
}
Expand All @@ -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);
Expand All @@ -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;
Expand Down Expand Up @@ -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);

Expand Down
18 changes: 15 additions & 3 deletions drivers/gpu/drm/drm_irq.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;

Expand Down Expand Up @@ -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;
Expand Down
Loading

0 comments on commit 4c44323

Please sign in to comment.