summaryrefslogtreecommitdiff
path: root/linux-core/drm_crtc.c
diff options
context:
space:
mode:
Diffstat (limited to 'linux-core/drm_crtc.c')
-rw-r--r--linux-core/drm_crtc.c471
1 files changed, 7 insertions, 464 deletions
diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c
index e05466ee..a4a51080 100644
--- a/linux-core/drm_crtc.c
+++ b/linux-core/drm_crtc.c
@@ -418,133 +418,6 @@ void drm_crtc_probe_output_modes(struct drm_device *dev, int maxX, int maxY)
}
EXPORT_SYMBOL(drm_crtc_probe_output_modes);
-/**
- * drm_crtc_set_mode - set a mode
- * @crtc: CRTC to program
- * @mode: mode to use
- * @x: width of mode
- * @y: height of mode
- *
- * LOCKING:
- * Caller must hold mode config lock.
- *
- * Try to set @mode on @crtc. Give @crtc and its associated outputs a chance
- * to fixup or reject the mode prior to trying to set it.
- *
- * RETURNS:
- * True if the mode was set successfully, or false otherwise.
- */
-bool drm_crtc_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode,
- int x, int y)
-{
- struct drm_device *dev = crtc->dev;
- struct drm_display_mode *adjusted_mode, saved_mode;
- int saved_x, saved_y;
- struct drm_output *output;
- bool ret = true;
-
- adjusted_mode = drm_mode_duplicate(dev, mode);
-
- crtc->enabled = drm_crtc_in_use(crtc);
-
- if (!crtc->enabled)
- return true;
-
- saved_mode = crtc->mode;
- saved_x = crtc->x;
- saved_y = crtc->y;
-
- /* Update crtc values up front so the driver can rely on them for mode
- * setting.
- */
- crtc->mode = *mode;
- crtc->x = x;
- crtc->y = y;
-
- if (drm_mode_equal(&saved_mode, &crtc->mode)) {
- if (saved_x != crtc->x || saved_y != crtc->y) {
- crtc->funcs->mode_set_base(crtc, crtc->x, crtc->y);
- goto done;
- }
- }
-
- /* Pass our mode to the outputs and the CRTC to give them a chance to
- * adjust it according to limitations or output properties, and also
- * a chance to reject the mode entirely.
- */
- list_for_each_entry(output, &dev->mode_config.output_list, head) {
-
- if (output->crtc != crtc)
- continue;
-
- if (!(ret = output->funcs->mode_fixup(output, mode, adjusted_mode))) {
- goto done;
- }
- }
-
- if (!(ret = crtc->funcs->mode_fixup(crtc, mode, adjusted_mode))) {
- goto done;
- }
-
- /* Prepare the outputs and CRTCs before setting the mode. */
- list_for_each_entry(output, &dev->mode_config.output_list, head) {
-
- if (output->crtc != crtc)
- continue;
-
- /* Disable the output as the first thing we do. */
- output->funcs->prepare(output);
- }
-
- crtc->funcs->prepare(crtc);
-
- /* Set up the DPLL and any output state that needs to adjust or depend
- * on the DPLL.
- */
- crtc->funcs->mode_set(crtc, mode, adjusted_mode, x, y);
-
- list_for_each_entry(output, &dev->mode_config.output_list, head) {
-
- if (output->crtc != crtc)
- continue;
-
- DRM_INFO("%s: set mode %s %x\n", drm_get_output_name(output), mode->name, mode->mode_id);
-
- output->funcs->mode_set(output, mode, adjusted_mode);
- }
-
- /* Now, enable the clocks, plane, pipe, and outputs that we set up. */
- crtc->funcs->commit(crtc);
-
- list_for_each_entry(output, &dev->mode_config.output_list, head) {
-
- if (output->crtc != crtc)
- continue;
-
- output->funcs->commit(output);
-
-#if 0 // TODO def RANDR_12_INTERFACE
- if (output->randr_output)
- RRPostPendingProperties (output->randr_output);
-#endif
- }
-
- /* XXX free adjustedmode */
- drm_mode_destroy(dev, adjusted_mode);
- /* TODO */
-// if (scrn->pScreen)
-// drm_crtc_set_screen_sub_pixel_order(dev);
-
-done:
- if (!ret) {
- crtc->mode = saved_mode;
- crtc->x = saved_x;
- crtc->y = saved_y;
- }
-
- return ret;
-}
-EXPORT_SYMBOL(drm_crtc_set_mode);
/**
* drm_disable_unused_functions - disable unused objects
@@ -896,171 +769,8 @@ out_err:
return ret;
}
-/**
- * drm_pick_crtcs - pick crtcs for output devices
- * @dev: DRM device
- *
- * LOCKING:
- * Caller must hold mode config lock.
- */
-static void drm_pick_crtcs (struct drm_device *dev)
-{
- int c, o, assigned;
- struct drm_output *output, *output_equal;
- struct drm_crtc *crtc;
- struct drm_display_mode *des_mode = NULL, *modes, *modes_equal;
- int found;
-
- list_for_each_entry(output, &dev->mode_config.output_list, head) {
- output->crtc = NULL;
-
- /* Don't hook up outputs that are disconnected ??
- *
- * This is debateable. Do we want fixed /dev/fbX or
- * dynamic on hotplug (need mode code for that though) ?
- *
- * If we don't hook up outputs now, then we only create
- * /dev/fbX for the output that's enabled, that's good as
- * the users console will be on that output.
- *
- * If we do hook up outputs that are disconnected now, then
- * the user may end up having to muck about with the fbcon
- * map flags to assign his console to the enabled output. Ugh.
- */
- if (output->status != output_status_connected)
- continue;
-
- if (list_empty(&output->modes))
- continue;
-
- des_mode = NULL;
- found = 0;
- list_for_each_entry(des_mode, &output->modes, head) {
- if (des_mode->type & DRM_MODE_TYPE_PREFERRED) {
- found = 1;
- break;
- }
- }
-
- /* No preferred mode, let's just select the first available */
- if (!found) {
- des_mode = NULL;
- list_for_each_entry(des_mode, &output->modes, head) {
- break;
- }
- }
-
- c = -1;
- list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
- assigned = 0;
- c++;
- if ((output->possible_crtcs & (1 << c)) == 0)
- continue;
-
- list_for_each_entry(output_equal, &dev->mode_config.output_list, head) {
- if (output->id == output_equal->id)
- continue;
-
- /* Find out if crtc has been assigned before */
- if (output_equal->crtc == crtc)
- assigned = 1;
- }
-
-#if 1 /* continue for now */
- if (assigned)
- continue;
-#endif
-
- o = -1;
- list_for_each_entry(output_equal, &dev->mode_config.output_list, head) {
- o++;
- if (output->id == output_equal->id)
- continue;
-
- list_for_each_entry(modes, &output->modes, head) {
- list_for_each_entry(modes_equal, &output_equal->modes, head) {
- if (drm_mode_equal (modes, modes_equal)) {
- if ((output->possible_clones & output_equal->possible_clones) && (output_equal->crtc == crtc)) {
- printk("Cloning %s (0x%lx) to %s (0x%lx)\n",drm_get_output_name(output),output->possible_clones,drm_get_output_name(output_equal),output_equal->possible_clones);
- des_mode = modes;
- assigned = 0;
- goto clone;
- }
- }
- }
- }
- }
-clone:
- /* crtc has been assigned skip it */
- if (assigned)
- continue;
-
- /* Found a CRTC to attach to, do it ! */
- output->crtc = crtc;
- output->crtc->desired_mode = des_mode;
- output->initial_x = 0;
- output->initial_y = 0;
- DRM_DEBUG("Desired mode for CRTC %d is 0x%x:%s\n",c,des_mode->mode_id, des_mode->name);
- break;
- }
- }
-}
-EXPORT_SYMBOL(drm_pick_crtcs);
-
-/**
- * drm_initial_config - setup a sane initial output configuration
- * @dev: DRM device
- * @can_grow: this configuration is growable
- *
- * LOCKING:
- * Called at init time, must take mode config lock.
- *
- * Scan the CRTCs and outputs and try to put together an initial setup.
- * At the moment, this is a cloned configuration across all heads with
- * a new framebuffer object as the backing store.
- *
- * RETURNS:
- * Zero if everything went ok, nonzero otherwise.
- */
-bool drm_initial_config(struct drm_device *dev, bool can_grow)
-{
- struct drm_output *output;
- struct drm_crtc *crtc;
- int ret = false;
-
- mutex_lock(&dev->mode_config.mutex);
-
- drm_crtc_probe_output_modes(dev, 2048, 2048);
-
- drm_pick_crtcs(dev);
-
- /* This is a little screwy, as we've already walked the outputs
- * above, but it's a little bit of magic too. There's the potential
- * for things not to get setup above if an existing device gets
- * re-assigned thus confusing the hardware. By walking the outputs
- * this fixes up their crtc's.
- */
- list_for_each_entry(output, &dev->mode_config.output_list, head) {
-
- /* can't setup the output if there's no assigned mode */
- if (!output->crtc || !output->crtc->desired_mode)
- continue;
-
- dev->driver->fb_probe(dev, output->crtc, output);
-
- /* and needs an attached fb */
- if (output->crtc->fb)
- drm_crtc_set_mode(output->crtc, output->crtc->desired_mode, 0, 0);
- }
-
- drm_disable_unused_functions(dev);
-
- mutex_unlock(&dev->mode_config.mutex);
- return ret;
-}
-EXPORT_SYMBOL(drm_initial_config);
/**
* drm_mode_config_cleanup - free up DRM mode_config info
@@ -1105,179 +815,7 @@ void drm_mode_config_cleanup(struct drm_device *dev)
}
EXPORT_SYMBOL(drm_mode_config_cleanup);
-/**
- * drm_crtc_set_config - set a new config from userspace
- * @crtc: CRTC to setup
- * @crtc_info: user provided configuration
- * @new_mode: new mode to set
- * @output_set: set of outputs for the new config
- * @fb: new framebuffer
- *
- * LOCKING:
- * Caller must hold mode config lock.
- *
- * Setup a new configuration, provided by the user in @crtc_info, and enable
- * it.
- *
- * RETURNS:
- * Zero. (FIXME)
- */
-int drm_crtc_set_config(struct drm_mode_set *set)
-{
- struct drm_device *dev;
- struct drm_crtc **save_crtcs, *new_crtc;
- bool save_enabled;
- bool changed = false;
- bool flip_or_move = false;
- struct drm_output *output;
- int count = 0, ro;
-
- DRM_DEBUG("\n");
-
- if (!set)
- return -EINVAL;
-
- if (!set->crtc)
- return -EINVAL;
-
- DRM_DEBUG("crtc: %p fb: %p outputs: %p num_outputs: %i (x, y) (%i, %i)\n", set->crtc, set->fb, set->outputs, set->num_outputs, set->x, set->y);
- dev = set->crtc->dev;
-
- /* save previous config */
- save_enabled = set->crtc->enabled;
-
- /* this is meant to be num_output not num_crtc */
- save_crtcs = kzalloc(dev->mode_config.num_output * sizeof(struct drm_crtc *), GFP_KERNEL);
- if (!save_crtcs)
- return -ENOMEM;
-
- /* 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)
- flip_or_move = true;
- if (set->x != set->crtc->x || set->y != set->crtc->y)
- flip_or_move = 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;
- }
-
- list_for_each_entry(output, &dev->mode_config.output_list, head) {
- save_crtcs[count++] = output->crtc;
-
- if (output->crtc == set->crtc)
- new_crtc = NULL;
- else
- new_crtc = output->crtc;
-
- for (ro = 0; ro < set->num_outputs; ro++) {
- if (set->outputs[ro] == output)
- new_crtc = set->crtc;
- }
- if (new_crtc != output->crtc) {
- changed = true;
- output->crtc = new_crtc;
- }
- }
-
- /* mode_set_base is not a required function */
- if (flip_or_move && !set->crtc->funcs->mode_set_base)
- changed = true;
-
- if (changed) {
- set->crtc->fb = set->fb;
- set->crtc->enabled = (set->mode != NULL);
- if (set->mode != NULL) {
- DRM_DEBUG("attempting to set mode from userspace\n");
- drm_mode_debug_printmodeline(set->mode);
- if (!drm_crtc_set_mode(set->crtc, set->mode, set->x,
- set->y)) {
- set->crtc->enabled = save_enabled;
- count = 0;
- list_for_each_entry(output, &dev->mode_config.output_list, head)
- output->crtc = save_crtcs[count++];
- kfree(save_crtcs);
- return -EINVAL;
- }
- /* TODO are these needed? */
- set->crtc->desired_x = set->x;
- set->crtc->desired_y = set->y;
- set->crtc->desired_mode = set->mode;
- }
- drm_disable_unused_functions(dev);
- } else if (flip_or_move) {
- if (set->crtc->fb != set->fb)
- set->crtc->fb = set->fb;
- set->crtc->funcs->mode_set_base(set->crtc, set->x, set->y);
- }
-
- kfree(save_crtcs);
- return 0;
-}
-EXPORT_SYMBOL(drm_crtc_set_config);
-
-/**
- * drm_hotplug_stage_two
- * @dev DRM device
- * @output hotpluged output
- *
- * LOCKING.
- * Caller must hold mode config lock, function might grab struct lock.
- *
- * Stage two of a hotplug.
- *
- * RETURNS:
- * Zero on success, errno on failure.
- */
-int drm_hotplug_stage_two(struct drm_device *dev, struct drm_output *output,
- bool connected)
-{
- int has_config = 0;
-
- dev->mode_config.hotplug_counter++;
-
- /* We might want to do something more here */
- if (!connected) {
- DRM_DEBUG("not connected\n");
- return 0;
- }
-
- if (output->crtc && output->crtc->desired_mode) {
- DRM_DEBUG("drm thinks that the output already has a config\n");
- has_config = 1;
- }
-
- drm_crtc_probe_output_modes(dev, 2048, 2048);
-
- if (!has_config)
- drm_pick_crtcs(dev);
-
- if (!output->crtc || !output->crtc->desired_mode) {
- DRM_DEBUG("could not find a desired mode or crtc for output\n");
- return 1;
- }
-
- /* We should really check if there is a fb using this crtc */
- if (!has_config)
- dev->driver->fb_probe(dev, output->crtc, output);
- else {
- dev->driver->fb_resize(dev, output->crtc);
-
- if (!drm_crtc_set_mode(output->crtc, output->crtc->desired_mode, 0, 0))
- DRM_ERROR("failed to set mode after hotplug\n");
- }
-
- drm_sysfs_hotplug_event(dev);
-
- drm_disable_unused_functions(dev);
-
- return 0;
-}
-EXPORT_SYMBOL(drm_hotplug_stage_two);
int drm_mode_hotplug_ioctl(struct drm_device *dev,
void *data, struct drm_file *file_priv)
@@ -1740,7 +1278,7 @@ int drm_mode_setcrtc(struct drm_device *dev,
set.outputs = output_set;
set.num_outputs = crtc_req->count_outputs;
set.fb =fb;
- ret = drm_crtc_set_config(&set);
+ ret = crtc->funcs->set_config(&set);
out:
kfree(output_set);
@@ -2535,7 +2073,6 @@ int drm_mode_replacefb(struct drm_device *dev,
{
struct drm_mode_fb_cmd *r = data;
struct drm_framebuffer *fb;
- struct drm_crtc *crtc;
struct drm_buffer_object *bo;
int found = 0;
struct drm_framebuffer *fbl = NULL;
@@ -2574,12 +2111,18 @@ int drm_mode_replacefb(struct drm_device *dev,
fb->depth = r->depth;
fb->bo = bo;
+ if (dev->mode_config.funcs->resize_fb)
+ dev->mode_config.funcs->resize_fb(dev, fb);
+ else
+ ret = -EINVAL;
+#if 0
/* find all crtcs connected to this fb */
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
if (crtc->fb->id == r->buffer_id) {
crtc->funcs->mode_set_base(crtc, crtc->x, crtc->y);
}
}
+#endif
out:
mutex_unlock(&dev->mode_config.mutex);
return ret;