From df8cd54286fbae5903d8ede390ec4a11cb6c4b6c Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 29 May 2008 14:02:14 +1000 Subject: modesetting: reorganise code into core and helper functions. This splits a lot of the core modesetting code out into a file of helper functions, that are only called from themselves and/or the driver. The driver gets called into more often or can call these functions from itself if it is a helper using driver. I've broken framebuffer resize doing this but I didn't like the API for that in any case. --- linux-core/drm_crtc_helper.c | 515 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 515 insertions(+) create mode 100644 linux-core/drm_crtc_helper.c (limited to 'linux-core/drm_crtc_helper.c') diff --git a/linux-core/drm_crtc_helper.c b/linux-core/drm_crtc_helper.c new file mode 100644 index 00000000..f776dbed --- /dev/null +++ b/linux-core/drm_crtc_helper.c @@ -0,0 +1,515 @@ + +/* + * Copyright (c) 2006-2007 Intel Corporation + * Copyright (c) 2007 Dave Airlie + * + * DRM core CRTC related functions + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + * + * Authors: + * Keith Packard + * Eric Anholt + * Dave Airlie + * Jesse Barnes + */ + +#include "drmP.h" +#include "drm_crtc.h" +#include "drm_crtc_helper.h" + + +/** + * 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_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_helper_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; + struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; + struct drm_output_helper_funcs *output_funcs; + 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; + output_funcs = output->helper_private; + 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; + output_funcs = output->helper_private; + /* 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 = output->helper_private; + 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 = output->helper_private; + 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_helper_set_mode); + + +/** + * drm_crtc_helper_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_helper_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; + struct drm_crtc_helper_funcs *crtc_funcs; + + DRM_DEBUG("\n"); + + if (!set) + return -EINVAL; + + if (!set->crtc) + return -EINVAL; + + if (!set->crtc->helper_private) + return -EINVAL; + + crtc_funcs = set->crtc->helper_private; + + 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 && !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_helper_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; + crtc_funcs->mode_set_base(set->crtc, set->x, set->y); + } + + kfree(save_crtcs); + return 0; +} +EXPORT_SYMBOL(drm_crtc_helper_set_config); + +/** + * 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_helper_initial_config(struct drm_device *dev, bool can_grow) +{ + struct drm_output *output; + 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_helper_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_helper_initial_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_helper_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 0 + if (!drm_crtc_set_mode(output->crtc, output->crtc->desired_mode, 0, 0)) + DRM_ERROR("failed to set mode after hotplug\n"); +#endif + } + + drm_sysfs_hotplug_event(dev); + + drm_disable_unused_functions(dev); + + return 0; +} +EXPORT_SYMBOL(drm_helper_hotplug_stage_two); -- cgit v1.2.3 From 9d38448ed33aaff324cc4bbe1e0878593e97d07d Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 30 May 2008 15:03:12 +1000 Subject: modesetting: the great renaming. Okay we have crtc, encoder and connectors. No more outputs exposed beyond driver internals I've broken intel tv connector stuff. Really for TV we should have one TV connector, with a sub property for the type of signal been driven over it --- linux-core/drm_crtc_helper.c | 186 +++++++++++++++++++++---------------------- 1 file changed, 93 insertions(+), 93 deletions(-) (limited to 'linux-core/drm_crtc_helper.c') diff --git a/linux-core/drm_crtc_helper.c b/linux-core/drm_crtc_helper.c index f776dbed..98b112ed 100644 --- a/linux-core/drm_crtc_helper.c +++ b/linux-core/drm_crtc_helper.c @@ -36,7 +36,7 @@ /** - * drm_pick_crtcs - pick crtcs for output devices + * drm_pick_crtcs - pick crtcs for connector devices * @dev: DRM device * * LOCKING: @@ -45,36 +45,36 @@ static void drm_pick_crtcs (struct drm_device *dev) { int c, o, assigned; - struct drm_output *output, *output_equal; + struct drm_connector *connector, *connector_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; + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + connector->crtc = NULL; - /* Don't hook up outputs that are disconnected ?? + /* Don't hook up connectors 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 don't hook up connectors now, then we only create + * /dev/fbX for the connector that's enabled, that's good as + * the users console will be on that connector. * - * If we do hook up outputs that are disconnected now, then + * If we do hook up connectors 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. + * map flags to assign his console to the enabled connector. Ugh. */ - if (output->status != output_status_connected) + if (connector->status != connector_status_connected) continue; - if (list_empty(&output->modes)) + if (list_empty(&connector->modes)) continue; des_mode = NULL; found = 0; - list_for_each_entry(des_mode, &output->modes, head) { + list_for_each_entry(des_mode, &connector->modes, head) { if (des_mode->type & DRM_MODE_TYPE_PREFERRED) { found = 1; break; @@ -84,7 +84,7 @@ static void drm_pick_crtcs (struct drm_device *dev) /* No preferred mode, let's just select the first available */ if (!found) { des_mode = NULL; - list_for_each_entry(des_mode, &output->modes, head) { + list_for_each_entry(des_mode, &connector->modes, head) { break; } } @@ -94,15 +94,15 @@ static void drm_pick_crtcs (struct drm_device *dev) assigned = 0; c++; - if ((output->possible_crtcs & (1 << c)) == 0) + if ((connector->possible_crtcs & (1 << c)) == 0) continue; - list_for_each_entry(output_equal, &dev->mode_config.output_list, head) { - if (output->id == output_equal->id) + list_for_each_entry(connector_equal, &dev->mode_config.connector_list, head) { + if (connector->id == connector_equal->id) continue; /* Find out if crtc has been assigned before */ - if (output_equal->crtc == crtc) + if (connector_equal->crtc == crtc) assigned = 1; } @@ -112,16 +112,16 @@ static void drm_pick_crtcs (struct drm_device *dev) #endif o = -1; - list_for_each_entry(output_equal, &dev->mode_config.output_list, head) { + list_for_each_entry(connector_equal, &dev->mode_config.connector_list, head) { o++; - if (output->id == output_equal->id) + if (connector->id == connector_equal->id) continue; - list_for_each_entry(modes, &output->modes, head) { - list_for_each_entry(modes_equal, &output_equal->modes, head) { + list_for_each_entry(modes, &connector->modes, head) { + list_for_each_entry(modes_equal, &connector_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); + if ((connector->possible_clones & connector_equal->possible_clones) && (connector_equal->crtc == crtc)) { + printk("Cloning %s (0x%lx) to %s (0x%lx)\n",drm_get_connector_name(connector),connector->possible_clones,drm_get_connector_name(connector_equal),connector_equal->possible_clones); des_mode = modes; assigned = 0; goto clone; @@ -137,10 +137,10 @@ clone: 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; + connector->crtc = crtc; + connector->crtc->desired_mode = des_mode; + connector->initial_x = 0; + connector->initial_y = 0; DRM_DEBUG("Desired mode for CRTC %d is 0x%x:%s\n",c,des_mode->mode_id, des_mode->name); break; } @@ -158,7 +158,7 @@ EXPORT_SYMBOL(drm_pick_crtcs); * LOCKING: * Caller must hold mode config lock. * - * Try to set @mode on @crtc. Give @crtc and its associated outputs a chance + * Try to set @mode on @crtc. Give @crtc and its associated connectors a chance * to fixup or reject the mode prior to trying to set it. * * RETURNS: @@ -170,9 +170,9 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mo struct drm_device *dev = crtc->dev; struct drm_display_mode *adjusted_mode, saved_mode; struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; - struct drm_output_helper_funcs *output_funcs; + struct drm_connector_helper_funcs *connector_funcs; int saved_x, saved_y; - struct drm_output *output; + struct drm_connector *connector; bool ret = true; adjusted_mode = drm_mode_duplicate(dev, mode); @@ -200,16 +200,16 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mo } } - /* 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 + /* Pass our mode to the connectors and the CRTC to give them a chance to + * adjust it according to limitations or connector properties, and also * a chance to reject the mode entirely. */ - list_for_each_entry(output, &dev->mode_config.output_list, head) { + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - if (output->crtc != crtc) + if (connector->crtc != crtc) continue; - output_funcs = output->helper_private; - if (!(ret = output_funcs->mode_fixup(output, mode, adjusted_mode))) { + connector_funcs = connector->helper_private; + if (!(ret = connector_funcs->mode_fixup(connector, mode, adjusted_mode))) { goto done; } } @@ -218,47 +218,47 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mo goto done; } - /* Prepare the outputs and CRTCs before setting the mode. */ - list_for_each_entry(output, &dev->mode_config.output_list, head) { + /* Prepare the connectors and CRTCs before setting the mode. */ + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - if (output->crtc != crtc) + if (connector->crtc != crtc) continue; - output_funcs = output->helper_private; - /* Disable the output as the first thing we do. */ - output_funcs->prepare(output); + connector_funcs = connector->helper_private; + /* Disable the connector as the first thing we do. */ + connector_funcs->prepare(connector); } crtc_funcs->prepare(crtc); - /* Set up the DPLL and any output state that needs to adjust or depend + /* Set up the DPLL and any connector 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) { + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - if (output->crtc != crtc) + if (connector->crtc != crtc) continue; - DRM_INFO("%s: set mode %s %x\n", drm_get_output_name(output), mode->name, mode->mode_id); - output_funcs = output->helper_private; - output_funcs->mode_set(output, mode, adjusted_mode); + DRM_INFO("%s: set mode %s %x\n", drm_get_connector_name(connector), mode->name, mode->mode_id); + connector_funcs = connector->helper_private; + connector_funcs->mode_set(connector, mode, adjusted_mode); } - /* Now, enable the clocks, plane, pipe, and outputs that we set up. */ + /* Now, enable the clocks, plane, pipe, and connectors that we set up. */ crtc_funcs->commit(crtc); - list_for_each_entry(output, &dev->mode_config.output_list, head) { + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - if (output->crtc != crtc) + if (connector->crtc != crtc) continue; - output_funcs = output->helper_private; - output_funcs->commit(output); + connector_funcs = connector->helper_private; + connector_funcs->commit(connector); #if 0 // TODO def RANDR_12_INTERFACE - if (output->randr_output) - RRPostPendingProperties (output->randr_output); + if (connector->randr_connector) + RRPostPendingProperties (connector->randr_connector); #endif } @@ -285,7 +285,7 @@ EXPORT_SYMBOL(drm_crtc_helper_set_mode); * @crtc: CRTC to setup * @crtc_info: user provided configuration * @new_mode: new mode to set - * @output_set: set of outputs for the new config + * @connector_set: set of connectors for the new config * @fb: new framebuffer * * LOCKING: @@ -304,7 +304,7 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) bool save_enabled; bool changed = false; bool flip_or_move = false; - struct drm_output *output; + struct drm_connector *connector; int count = 0, ro; struct drm_crtc_helper_funcs *crtc_funcs; @@ -321,14 +321,14 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) crtc_funcs = set->crtc->helper_private; - 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); + DRM_DEBUG("crtc: %p fb: %p connectors: %p num_connectors: %i (x, y) (%i, %i)\n", set->crtc, set->fb, set->connectors, set->num_connectors, 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); + /* this is meant to be num_connector not num_crtc */ + save_crtcs = kzalloc(dev->mode_config.num_connector * sizeof(struct drm_crtc *), GFP_KERNEL); if (!save_crtcs) return -ENOMEM; @@ -347,21 +347,21 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) changed = true; } - list_for_each_entry(output, &dev->mode_config.output_list, head) { - save_crtcs[count++] = output->crtc; + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + save_crtcs[count++] = connector->crtc; - if (output->crtc == set->crtc) + if (connector->crtc == set->crtc) new_crtc = NULL; else - new_crtc = output->crtc; + new_crtc = connector->crtc; - for (ro = 0; ro < set->num_outputs; ro++) { - if (set->outputs[ro] == output) + for (ro = 0; ro < set->num_connectors; ro++) { + if (set->connectors[ro] == connector) new_crtc = set->crtc; } - if (new_crtc != output->crtc) { + if (new_crtc != connector->crtc) { changed = true; - output->crtc = new_crtc; + connector->crtc = new_crtc; } } @@ -379,8 +379,8 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) 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++]; + list_for_each_entry(connector, &dev->mode_config.connector_list, head) + connector->crtc = save_crtcs[count++]; kfree(save_crtcs); return -EINVAL; } @@ -402,14 +402,14 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) EXPORT_SYMBOL(drm_crtc_helper_set_config); /** - * drm_initial_config - setup a sane initial output configuration + * drm_initial_config - setup a sane initial connector 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. + * Scan the CRTCs and connectors 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. * @@ -418,32 +418,32 @@ EXPORT_SYMBOL(drm_crtc_helper_set_config); */ bool drm_helper_initial_config(struct drm_device *dev, bool can_grow) { - struct drm_output *output; + struct drm_connector *connector; int ret = false; mutex_lock(&dev->mode_config.mutex); - drm_crtc_probe_output_modes(dev, 2048, 2048); + drm_crtc_probe_connector_modes(dev, 2048, 2048); drm_pick_crtcs(dev); - /* This is a little screwy, as we've already walked the outputs + /* This is a little screwy, as we've already walked the connectors * 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 + * re-assigned thus confusing the hardware. By walking the connectors * this fixes up their crtc's. */ - list_for_each_entry(output, &dev->mode_config.output_list, head) { + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - /* can't setup the output if there's no assigned mode */ - if (!output->crtc || !output->crtc->desired_mode) + /* can't setup the connector if there's no assigned mode */ + if (!connector->crtc || !connector->crtc->desired_mode) continue; - dev->driver->fb_probe(dev, output->crtc, output); + dev->driver->fb_probe(dev, connector->crtc, connector); /* and needs an attached fb */ - if (output->crtc->fb) - drm_crtc_helper_set_mode(output->crtc, output->crtc->desired_mode, 0, 0); + if (connector->crtc->fb) + drm_crtc_helper_set_mode(connector->crtc, connector->crtc->desired_mode, 0, 0); } drm_disable_unused_functions(dev); @@ -456,7 +456,7 @@ EXPORT_SYMBOL(drm_helper_initial_config); /** * drm_hotplug_stage_two * @dev DRM device - * @output hotpluged output + * @connector hotpluged connector * * LOCKING. * Caller must hold mode config lock, function might grab struct lock. @@ -466,7 +466,7 @@ EXPORT_SYMBOL(drm_helper_initial_config); * RETURNS: * Zero on success, errno on failure. */ -int drm_helper_hotplug_stage_two(struct drm_device *dev, struct drm_output *output, +int drm_helper_hotplug_stage_two(struct drm_device *dev, struct drm_connector *connector, bool connected) { int has_config = 0; @@ -479,29 +479,29 @@ int drm_helper_hotplug_stage_two(struct drm_device *dev, struct drm_output *outp return 0; } - if (output->crtc && output->crtc->desired_mode) { - DRM_DEBUG("drm thinks that the output already has a config\n"); + if (connector->crtc && connector->crtc->desired_mode) { + DRM_DEBUG("drm thinks that the connector already has a config\n"); has_config = 1; } - drm_crtc_probe_output_modes(dev, 2048, 2048); + drm_crtc_probe_connector_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"); + if (!connector->crtc || !connector->crtc->desired_mode) { + DRM_DEBUG("could not find a desired mode or crtc for connector\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); + dev->driver->fb_probe(dev, connector->crtc, connector); else { - dev->driver->fb_resize(dev, output->crtc); + dev->driver->fb_resize(dev, connector->crtc); #if 0 - if (!drm_crtc_set_mode(output->crtc, output->crtc->desired_mode, 0, 0)) + if (!drm_crtc_set_mode(connector->crtc, connector->crtc->desired_mode, 0, 0)) DRM_ERROR("failed to set mode after hotplug\n"); #endif } -- cgit v1.2.3 From 5d47185eb69d73dd7e6ee3ddde4d0c7642c2d5b7 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 30 May 2008 15:32:58 +1000 Subject: drm: switch possible crtc/clones over to encoders --- linux-core/drm_crtc_helper.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) (limited to 'linux-core/drm_crtc_helper.c') diff --git a/linux-core/drm_crtc_helper.c b/linux-core/drm_crtc_helper.c index 98b112ed..e5774ccc 100644 --- a/linux-core/drm_crtc_helper.c +++ b/linux-core/drm_crtc_helper.c @@ -46,6 +46,7 @@ static void drm_pick_crtcs (struct drm_device *dev) { int c, o, assigned; struct drm_connector *connector, *connector_equal; + struct drm_encoder *encoder, *encoder_equal; struct drm_crtc *crtc; struct drm_display_mode *des_mode = NULL, *modes, *modes_equal; int found; @@ -89,12 +90,16 @@ static void drm_pick_crtcs (struct drm_device *dev) } } + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) + if (encoder->id == connector->current_encoder_id) + break; + c = -1; list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { assigned = 0; c++; - if ((connector->possible_crtcs & (1 << c)) == 0) + if ((encoder->possible_crtcs & (1 << c)) == 0) continue; list_for_each_entry(connector_equal, &dev->mode_config.connector_list, head) { @@ -117,11 +122,15 @@ static void drm_pick_crtcs (struct drm_device *dev) if (connector->id == connector_equal->id) continue; + list_for_each_entry(encoder_equal, &dev->mode_config.encoder_list, head) + if (encoder_equal->id == connector_equal->current_encoder_id) + break; + list_for_each_entry(modes, &connector->modes, head) { list_for_each_entry(modes_equal, &connector_equal->modes, head) { if (drm_mode_equal (modes, modes_equal)) { - if ((connector->possible_clones & connector_equal->possible_clones) && (connector_equal->crtc == crtc)) { - printk("Cloning %s (0x%lx) to %s (0x%lx)\n",drm_get_connector_name(connector),connector->possible_clones,drm_get_connector_name(connector_equal),connector_equal->possible_clones); + if ((encoder->possible_clones & encoder_equal->possible_clones) && (connector_equal->crtc == crtc)) { + printk("Cloning %s (0x%lx) to %s (0x%lx)\n",drm_get_connector_name(connector),encoder->possible_clones,drm_get_connector_name(connector_equal),encoder_equal->possible_clones); des_mode = modes; assigned = 0; goto clone; -- cgit v1.2.3 From e439e74776b215d70d8e34e8aa9cea22179dcbc6 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 2 Jun 2008 10:05:54 +1000 Subject: drm/modesetting: another re-org of some internals. Move dpms into the helper functions. Move crtc into the encoder. Move disable unused functions into the helper. --- linux-core/drm_crtc_helper.c | 136 ++++++++++++++++++++++++++----------------- 1 file changed, 81 insertions(+), 55 deletions(-) (limited to 'linux-core/drm_crtc_helper.c') diff --git a/linux-core/drm_crtc_helper.c b/linux-core/drm_crtc_helper.c index e5774ccc..82862b55 100644 --- a/linux-core/drm_crtc_helper.c +++ b/linux-core/drm_crtc_helper.c @@ -34,6 +34,35 @@ #include "drm_crtc.h" #include "drm_crtc_helper.h" +/** + * drm_disable_unused_functions - disable unused objects + * @dev: DRM device + * + * LOCKING: + * Caller must hold mode config lock. + * + * If an connector or CRTC isn't part of @dev's mode_config, it can be disabled + * by calling its dpms function, which should power it off. + */ +void drm_helper_disable_unused_functions(struct drm_device *dev) +{ + struct drm_encoder *encoder; + struct drm_encoder_helper_funcs *encoder_funcs; + struct drm_crtc *crtc; + + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + encoder_funcs = encoder->helper_private; + if (!encoder->crtc) + (*encoder_funcs->dpms)(encoder, DPMSModeOff); + } + + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; + if (!crtc->enabled) + crtc_funcs->dpms(crtc, DPMSModeOff); + } +} +EXPORT_SYMBOL(drm_helper_disable_unused_functions); /** * drm_pick_crtcs - pick crtcs for connector devices @@ -52,7 +81,7 @@ static void drm_pick_crtcs (struct drm_device *dev) int found; list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - connector->crtc = NULL; + connector->encoder->crtc = NULL; /* Don't hook up connectors that are disconnected ?? * @@ -90,9 +119,7 @@ static void drm_pick_crtcs (struct drm_device *dev) } } - list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) - if (encoder->id == connector->current_encoder_id) - break; + encoder = connector->encoder; c = -1; list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { @@ -107,7 +134,7 @@ static void drm_pick_crtcs (struct drm_device *dev) continue; /* Find out if crtc has been assigned before */ - if (connector_equal->crtc == crtc) + if (connector_equal->encoder->crtc == crtc) assigned = 1; } @@ -122,14 +149,12 @@ static void drm_pick_crtcs (struct drm_device *dev) if (connector->id == connector_equal->id) continue; - list_for_each_entry(encoder_equal, &dev->mode_config.encoder_list, head) - if (encoder_equal->id == connector_equal->current_encoder_id) - break; + encoder_equal = connector_equal->encoder; list_for_each_entry(modes, &connector->modes, head) { list_for_each_entry(modes_equal, &connector_equal->modes, head) { if (drm_mode_equal (modes, modes_equal)) { - if ((encoder->possible_clones & encoder_equal->possible_clones) && (connector_equal->crtc == crtc)) { + if ((encoder->possible_clones & encoder_equal->possible_clones) && (connector_equal->encoder->crtc == crtc)) { printk("Cloning %s (0x%lx) to %s (0x%lx)\n",drm_get_connector_name(connector),encoder->possible_clones,drm_get_connector_name(connector_equal),encoder_equal->possible_clones); des_mode = modes; assigned = 0; @@ -146,8 +171,8 @@ clone: continue; /* Found a CRTC to attach to, do it ! */ - connector->crtc = crtc; - connector->crtc->desired_mode = des_mode; + connector->encoder->crtc = crtc; + connector->encoder->crtc->desired_mode = des_mode; connector->initial_x = 0; connector->initial_y = 0; DRM_DEBUG("Desired mode for CRTC %d is 0x%x:%s\n",c,des_mode->mode_id, des_mode->name); @@ -179,9 +204,9 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mo struct drm_device *dev = crtc->dev; struct drm_display_mode *adjusted_mode, saved_mode; struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; - struct drm_connector_helper_funcs *connector_funcs; + struct drm_encoder_helper_funcs *encoder_funcs; int saved_x, saved_y; - struct drm_connector *connector; + struct drm_encoder *encoder; bool ret = true; adjusted_mode = drm_mode_duplicate(dev, mode); @@ -213,12 +238,12 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mo * adjust it according to limitations or connector properties, and also * a chance to reject the mode entirely. */ - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { - if (connector->crtc != crtc) + if (encoder->crtc != crtc) continue; - connector_funcs = connector->helper_private; - if (!(ret = connector_funcs->mode_fixup(connector, mode, adjusted_mode))) { + encoder_funcs = encoder->helper_private; + if (!(ret = encoder_funcs->mode_fixup(encoder, mode, adjusted_mode))) { goto done; } } @@ -227,48 +252,44 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mo goto done; } - /* Prepare the connectors and CRTCs before setting the mode. */ - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + /* Prepare the encoders and CRTCs before setting the mode. */ + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { - if (connector->crtc != crtc) + if (encoder->crtc != crtc) continue; - connector_funcs = connector->helper_private; - /* Disable the connector as the first thing we do. */ - connector_funcs->prepare(connector); + encoder_funcs = encoder->helper_private; + /* Disable the encoders as the first thing we do. */ + encoder_funcs->prepare(encoder); } crtc_funcs->prepare(crtc); - /* Set up the DPLL and any connector state that needs to adjust or depend + /* Set up the DPLL and any encoders state that needs to adjust or depend * on the DPLL. */ crtc_funcs->mode_set(crtc, mode, adjusted_mode, x, y); - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { - if (connector->crtc != crtc) + if (encoder->crtc != crtc) continue; - DRM_INFO("%s: set mode %s %x\n", drm_get_connector_name(connector), mode->name, mode->mode_id); - connector_funcs = connector->helper_private; - connector_funcs->mode_set(connector, mode, adjusted_mode); + DRM_INFO("%s: set mode %s %x\n", drm_get_encoder_name(encoder), mode->name, mode->mode_id); + encoder_funcs = encoder->helper_private; + encoder_funcs->mode_set(encoder, mode, adjusted_mode); } /* Now, enable the clocks, plane, pipe, and connectors that we set up. */ crtc_funcs->commit(crtc); - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { - if (connector->crtc != crtc) + if (encoder->crtc != crtc) continue; - connector_funcs = connector->helper_private; - connector_funcs->commit(connector); + encoder_funcs = encoder->helper_private; + encoder_funcs->commit(encoder); -#if 0 // TODO def RANDR_12_INTERFACE - if (connector->randr_connector) - RRPostPendingProperties (connector->randr_connector); -#endif } /* XXX free adjustedmode */ @@ -357,20 +378,23 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) } list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - save_crtcs[count++] = connector->crtc; + if (!connector->encoder) + continue; - if (connector->crtc == set->crtc) + save_crtcs[count++] = connector->encoder->crtc; + + if (connector->encoder->crtc == set->crtc) new_crtc = NULL; else - new_crtc = connector->crtc; + new_crtc = connector->encoder->crtc; for (ro = 0; ro < set->num_connectors; ro++) { if (set->connectors[ro] == connector) new_crtc = set->crtc; } - if (new_crtc != connector->crtc) { + if (new_crtc != connector->encoder->crtc) { changed = true; - connector->crtc = new_crtc; + connector->encoder->crtc = new_crtc; } } @@ -389,7 +413,7 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) set->crtc->enabled = save_enabled; count = 0; list_for_each_entry(connector, &dev->mode_config.connector_list, head) - connector->crtc = save_crtcs[count++]; + connector->encoder->crtc = save_crtcs[count++]; kfree(save_crtcs); return -EINVAL; } @@ -398,7 +422,7 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) set->crtc->desired_y = set->y; set->crtc->desired_mode = set->mode; } - drm_disable_unused_functions(dev); + drm_helper_disable_unused_functions(dev); } else if (flip_or_move) { if (set->crtc->fb != set->fb) set->crtc->fb = set->fb; @@ -444,18 +468,19 @@ bool drm_helper_initial_config(struct drm_device *dev, bool can_grow) */ list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + struct drm_crtc *crtc = connector->encoder->crtc; /* can't setup the connector if there's no assigned mode */ - if (!connector->crtc || !connector->crtc->desired_mode) + if (!crtc || !crtc->desired_mode) continue; - dev->driver->fb_probe(dev, connector->crtc, connector); + dev->driver->fb_probe(dev, crtc, connector); /* and needs an attached fb */ - if (connector->crtc->fb) - drm_crtc_helper_set_mode(connector->crtc, connector->crtc->desired_mode, 0, 0); + if (crtc->fb) + drm_crtc_helper_set_mode(crtc, crtc->desired_mode, 0, 0); } - drm_disable_unused_functions(dev); + drm_helper_disable_unused_functions(dev); mutex_unlock(&dev->mode_config.mutex); return ret; @@ -488,7 +513,7 @@ int drm_helper_hotplug_stage_two(struct drm_device *dev, struct drm_connector *c return 0; } - if (connector->crtc && connector->crtc->desired_mode) { + if (connector->encoder->crtc && connector->encoder->crtc->desired_mode) { DRM_DEBUG("drm thinks that the connector already has a config\n"); has_config = 1; } @@ -498,27 +523,28 @@ int drm_helper_hotplug_stage_two(struct drm_device *dev, struct drm_connector *c if (!has_config) drm_pick_crtcs(dev); - if (!connector->crtc || !connector->crtc->desired_mode) { + if (!connector->encoder->crtc || !connector->encoder->crtc->desired_mode) { DRM_DEBUG("could not find a desired mode or crtc for connector\n"); return 1; } /* We should really check if there is a fb using this crtc */ if (!has_config) - dev->driver->fb_probe(dev, connector->crtc, connector); + dev->driver->fb_probe(dev, connector->encoder->crtc, connector); else { - dev->driver->fb_resize(dev, connector->crtc); + dev->driver->fb_resize(dev, connector->encoder->crtc); #if 0 - if (!drm_crtc_set_mode(connector->crtc, connector->crtc->desired_mode, 0, 0)) + if (!drm_crtc_set_mode(connector->encoder->crtc, connector->encoder->crtc->desired_mode, 0, 0)) DRM_ERROR("failed to set mode after hotplug\n"); #endif } drm_sysfs_hotplug_event(dev); - drm_disable_unused_functions(dev); + drm_helper_disable_unused_functions(dev); return 0; } EXPORT_SYMBOL(drm_helper_hotplug_stage_two); + -- cgit v1.2.3 From 0dd000b578adec6ff101c957bce7dc9a32b76713 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 2 Jun 2008 11:12:28 +1000 Subject: drm/modesetting: move some connector functions to helper. Migrated the output mode collection into the helper. --- linux-core/drm_crtc_helper.c | 140 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 135 insertions(+), 5 deletions(-) (limited to 'linux-core/drm_crtc_helper.c') diff --git a/linux-core/drm_crtc_helper.c b/linux-core/drm_crtc_helper.c index 82862b55..f1a72707 100644 --- a/linux-core/drm_crtc_helper.c +++ b/linux-core/drm_crtc_helper.c @@ -34,6 +34,136 @@ #include "drm_crtc.h" #include "drm_crtc_helper.h" +/* + * Detailed mode info for a standard 640x480@60Hz monitor + */ +static struct drm_display_mode std_mode[] = { + { DRM_MODE("640x480", DRM_MODE_TYPE_DEFAULT, 25200, 640, 656, + 752, 800, 0, 480, 490, 492, 525, 0, + V_NHSYNC | V_NVSYNC) }, /* 640x480@60Hz */ +}; + +/** + * drm_helper_probe_connector_modes - get complete set of display modes + * @dev: DRM device + * @maxX: max width for modes + * @maxY: max height for modes + * + * LOCKING: + * Caller must hold mode config lock. + * + * Based on @dev's mode_config layout, scan all the connectors and try to detect + * modes on them. Modes will first be added to the connector's probed_modes + * list, then culled (based on validity and the @maxX, @maxY parameters) and + * put into the normal modes list. + * + * Intended to be used either at bootup time or when major configuration + * changes have occurred. + * + * FIXME: take into account monitor limits + */ +void 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; + + /* set all modes to the unverified state */ + list_for_each_entry_safe(mode, t, &connector->modes, head) + mode->status = MODE_UNVERIFIED; + + connector->status = (*connector->funcs->detect)(connector); + + if (connector->status == connector_status_disconnected) { + DRM_DEBUG("%s is disconnected\n", drm_get_connector_name(connector)); + /* TODO set EDID to NULL */ + return; + } + + ret = (*connector_funcs->get_modes)(connector); + + if (ret) { + drm_mode_connector_list_update(connector); + } + + if (maxX && maxY) + drm_mode_validate_size(dev, &connector->modes, maxX, + maxY, 0); + list_for_each_entry_safe(mode, t, &connector->modes, head) { + if (mode->status == MODE_OK) + mode->status = (*connector_funcs->mode_valid)(connector,mode); + } + + + 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)); + } + + drm_mode_sort(&connector->modes); + + DRM_DEBUG("Probed modes for %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); + } +} +EXPORT_SYMBOL(drm_helper_probe_single_connector_modes); + +void drm_helper_probe_connector_modes(struct drm_device *dev, uint32_t maxX, uint32_t maxY) +{ + struct drm_connector *connector; + + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + drm_helper_probe_single_connector_modes(connector, maxX, maxY); + } +} +EXPORT_SYMBOL(drm_helper_probe_connector_modes); + + +/** + * drm_helper_crtc_in_use - check if a given CRTC is in a mode_config + * @crtc: CRTC to check + * + * LOCKING: + * Caller must hold mode config lock. + * + * Walk @crtc's DRM device's mode_config and see if it's in use. + * + * RETURNS: + * True if @crtc is part of the mode_config, false otherwise. + */ +bool drm_helper_crtc_in_use(struct drm_crtc *crtc) +{ + struct drm_encoder *encoder; + struct drm_device *dev = crtc->dev; + /* FIXME: Locking around list access? */ + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) + if (encoder->crtc == crtc) + return true; + return false; +} +EXPORT_SYMBOL(drm_helper_crtc_in_use); + /** * drm_disable_unused_functions - disable unused objects * @dev: DRM device @@ -81,8 +211,8 @@ static void drm_pick_crtcs (struct drm_device *dev) int found; list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - connector->encoder->crtc = NULL; - + connector->encoder->crtc = NULL; + /* Don't hook up connectors that are disconnected ?? * * This is debateable. Do we want fixed /dev/fbX or @@ -211,7 +341,7 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mo adjusted_mode = drm_mode_duplicate(dev, mode); - crtc->enabled = drm_crtc_in_use(crtc); + crtc->enabled = drm_helper_crtc_in_use(crtc); if (!crtc->enabled) return true; @@ -456,7 +586,7 @@ bool drm_helper_initial_config(struct drm_device *dev, bool can_grow) mutex_lock(&dev->mode_config.mutex); - drm_crtc_probe_connector_modes(dev, 2048, 2048); + drm_helper_probe_connector_modes(dev, 2048, 2048); drm_pick_crtcs(dev); @@ -518,7 +648,7 @@ int drm_helper_hotplug_stage_two(struct drm_device *dev, struct drm_connector *c has_config = 1; } - drm_crtc_probe_connector_modes(dev, 2048, 2048); + drm_helper_probe_connector_modes(dev, 2048, 2048); if (!has_config) drm_pick_crtcs(dev); -- cgit v1.2.3 From 46c78a2223802b9105a87b7125fd4872ab69c4ca Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 2 Jun 2008 11:44:35 +1000 Subject: drm/modesetting: add best encoder finding for modesetting This asks the driver to suggest the best encoder for the connector during the pick crtcs stage. Need to also do this during mode setting stages --- linux-core/drm_crtc_helper.c | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) (limited to 'linux-core/drm_crtc_helper.c') diff --git a/linux-core/drm_crtc_helper.c b/linux-core/drm_crtc_helper.c index f1a72707..a4168f68 100644 --- a/linux-core/drm_crtc_helper.c +++ b/linux-core/drm_crtc_helper.c @@ -208,10 +208,17 @@ static void drm_pick_crtcs (struct drm_device *dev) struct drm_encoder *encoder, *encoder_equal; struct drm_crtc *crtc; struct drm_display_mode *des_mode = NULL, *modes, *modes_equal; + struct drm_connector_helper_funcs *connector_funcs; int found; + /* clean out all the encoder/crtc combos */ + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + encoder->crtc = NULL; + } + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - connector->encoder->crtc = NULL; + connector_funcs = connector->helper_private; + connector->encoder = NULL; /* Don't hook up connectors that are disconnected ?? * @@ -249,7 +256,11 @@ static void drm_pick_crtcs (struct drm_device *dev) } } - encoder = connector->encoder; + encoder = connector_funcs->best_encoder(connector); + if (!encoder) + continue; + + connector->encoder = encoder; c = -1; list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { @@ -259,12 +270,12 @@ static void drm_pick_crtcs (struct drm_device *dev) if ((encoder->possible_crtcs & (1 << c)) == 0) continue; - list_for_each_entry(connector_equal, &dev->mode_config.connector_list, head) { - if (connector->id == connector_equal->id) + list_for_each_entry(encoder_equal, &dev->mode_config.encoder_list, head) { + if (encoder->id == encoder_equal->id) continue; /* Find out if crtc has been assigned before */ - if (connector_equal->encoder->crtc == crtc) + if (encoder_equal->crtc == crtc) assigned = 1; } @@ -281,6 +292,9 @@ static void drm_pick_crtcs (struct drm_device *dev) encoder_equal = connector_equal->encoder; + if (!encoder_equal) + continue; + list_for_each_entry(modes, &connector->modes, head) { list_for_each_entry(modes_equal, &connector_equal->modes, head) { if (drm_mode_equal (modes, modes_equal)) { @@ -301,8 +315,8 @@ clone: continue; /* Found a CRTC to attach to, do it ! */ - connector->encoder->crtc = crtc; - connector->encoder->crtc->desired_mode = des_mode; + encoder->crtc = crtc; + encoder->crtc->desired_mode = des_mode; connector->initial_x = 0; connector->initial_y = 0; DRM_DEBUG("Desired mode for CRTC %d is 0x%x:%s\n",c,des_mode->mode_id, des_mode->name); -- cgit v1.2.3 From 7fec6c0e2a2457925b88ed3bd70d9defde77b81b Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 2 Jun 2008 12:57:09 +1000 Subject: drm: fixup encoder picking in set_config stage --- linux-core/drm_crtc_helper.c | 68 ++++++++++++++++++++++++++++++++++++++------ 1 file changed, 59 insertions(+), 9 deletions(-) (limited to 'linux-core/drm_crtc_helper.c') diff --git a/linux-core/drm_crtc_helper.c b/linux-core/drm_crtc_helper.c index a4168f68..2ceaa860 100644 --- a/linux-core/drm_crtc_helper.c +++ b/linux-core/drm_crtc_helper.c @@ -386,7 +386,7 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mo if (encoder->crtc != crtc) continue; - encoder_funcs = encoder->helper_private; + encoder_funcs = encoder->helper_private; if (!(ret = encoder_funcs->mode_fixup(encoder, mode, adjusted_mode))) { goto done; } @@ -475,12 +475,14 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) { struct drm_device *dev; struct drm_crtc **save_crtcs, *new_crtc; + struct drm_encoder **save_encoders, *new_encoder; bool save_enabled; bool changed = false; bool flip_or_move = false; struct drm_connector *connector; - int count = 0, ro; + int count = 0, ro, fail = 0; struct drm_crtc_helper_funcs *crtc_funcs; + int ret = 0; DRM_DEBUG("\n"); @@ -506,6 +508,12 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) if (!save_crtcs) return -ENOMEM; + save_encoders = kzalloc(dev->mode_config.num_connector * sizeof(struct drm_encoders *), GFP_KERNEL); + if (!save_encoders) { + kfree(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) @@ -521,6 +529,35 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) changed = true; } + /* a) traverse passed in connector list and get encoders for them */ + count = 0; + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + struct drm_connector_helper_funcs *connector_funcs = connector->helper_private; + save_encoders[count++] = connector->encoder; + new_encoder = NULL; + for (ro = 0; ro < set->num_connectors; ro++) { + if (set->connectors[ro] == connector) { + new_encoder = connector_funcs->best_encoder(connector); + /* if we can't get an encoder for a connector + we are setting now - then fail */ + if (new_encoder == NULL) + /* don't break so fail path works correct */ + fail = 1; + break; + } + } + + if (new_encoder != connector->encoder) { + changed = true; + connector->encoder = new_encoder; + } + } + + if (fail) { + ret = -EINVAL; + goto fail_no_encoder; + } + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { if (!connector->encoder) continue; @@ -553,13 +590,9 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) DRM_DEBUG("attempting to set mode from userspace\n"); drm_mode_debug_printmodeline(set->mode); if (!drm_crtc_helper_set_mode(set->crtc, set->mode, set->x, - set->y)) { - set->crtc->enabled = save_enabled; - count = 0; - list_for_each_entry(connector, &dev->mode_config.connector_list, head) - connector->encoder->crtc = save_crtcs[count++]; - kfree(save_crtcs); - return -EINVAL; + set->y)) { + ret = -EINVAL; + goto fail_set_mode; } /* TODO are these needed? */ set->crtc->desired_x = set->x; @@ -573,8 +606,25 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) crtc_funcs->mode_set_base(set->crtc, set->x, set->y); } + kfree(save_encoders); kfree(save_crtcs); return 0; + +fail_set_mode: + set->crtc->enabled = save_enabled; + count = 0; + list_for_each_entry(connector, &dev->mode_config.connector_list, head) + connector->encoder->crtc = save_crtcs[count++]; +fail_no_encoder: + kfree(save_crtcs); + count = 0; + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + connector->encoder = save_encoders[count++]; + } + kfree(save_encoders); + return ret; + + } EXPORT_SYMBOL(drm_crtc_helper_set_config); -- cgit v1.2.3 From 50d3e5bd020d0b6877a5fef441408f16e31121cd Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 2 Jun 2008 16:19:21 +1000 Subject: drm/modesetting: redo object handles around a core object. handle crtc/encoders/connectors/fb/mode/property/blob using this system. --- linux-core/drm_crtc_helper.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'linux-core/drm_crtc_helper.c') diff --git a/linux-core/drm_crtc_helper.c b/linux-core/drm_crtc_helper.c index 2ceaa860..52a87da7 100644 --- a/linux-core/drm_crtc_helper.c +++ b/linux-core/drm_crtc_helper.c @@ -271,7 +271,7 @@ static void drm_pick_crtcs (struct drm_device *dev) continue; list_for_each_entry(encoder_equal, &dev->mode_config.encoder_list, head) { - if (encoder->id == encoder_equal->id) + if (encoder->base.id == encoder_equal->base.id) continue; /* Find out if crtc has been assigned before */ @@ -287,7 +287,7 @@ static void drm_pick_crtcs (struct drm_device *dev) o = -1; list_for_each_entry(connector_equal, &dev->mode_config.connector_list, head) { o++; - if (connector->id == connector_equal->id) + if (connector->base.id == connector_equal->base.id) continue; encoder_equal = connector_equal->encoder; @@ -319,7 +319,7 @@ clone: encoder->crtc->desired_mode = des_mode; connector->initial_x = 0; connector->initial_y = 0; - DRM_DEBUG("Desired mode for CRTC %d is 0x%x:%s\n",c,des_mode->mode_id, des_mode->name); + DRM_DEBUG("Desired mode for CRTC %d is 0x%x:%s\n",c,des_mode->base.id, des_mode->name); break; } } @@ -418,7 +418,7 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mo if (encoder->crtc != crtc) continue; - DRM_INFO("%s: set mode %s %x\n", drm_get_encoder_name(encoder), mode->name, mode->mode_id); + DRM_INFO("%s: set mode %s %x\n", drm_get_encoder_name(encoder), mode->name, mode->base.id); encoder_funcs = encoder->helper_private; encoder_funcs->mode_set(encoder, mode, adjusted_mode); } -- cgit v1.2.3 From dc022084cda0a5558f033c3caa657d5af84ef544 Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Mon, 2 Jun 2008 10:03:28 +0100 Subject: Fix warnings --- linux-core/drm_crtc_helper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'linux-core/drm_crtc_helper.c') diff --git a/linux-core/drm_crtc_helper.c b/linux-core/drm_crtc_helper.c index 52a87da7..a8c44b76 100644 --- a/linux-core/drm_crtc_helper.c +++ b/linux-core/drm_crtc_helper.c @@ -299,7 +299,7 @@ static void drm_pick_crtcs (struct drm_device *dev) list_for_each_entry(modes_equal, &connector_equal->modes, head) { if (drm_mode_equal (modes, modes_equal)) { if ((encoder->possible_clones & encoder_equal->possible_clones) && (connector_equal->encoder->crtc == crtc)) { - printk("Cloning %s (0x%lx) to %s (0x%lx)\n",drm_get_connector_name(connector),encoder->possible_clones,drm_get_connector_name(connector_equal),encoder_equal->possible_clones); + printk("Cloning %s (0x%x) to %s (0x%x)\n",drm_get_connector_name(connector),encoder->possible_clones,drm_get_connector_name(connector_equal),encoder_equal->possible_clones); des_mode = modes; assigned = 0; goto clone; -- cgit v1.2.3 From 3ed17803d826b10f8f94d09acf12877e9738823c Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Mon, 2 Jun 2008 10:44:29 +0100 Subject: more checks for NULL encoder so we don't segfault. --- linux-core/drm_crtc_helper.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'linux-core/drm_crtc_helper.c') diff --git a/linux-core/drm_crtc_helper.c b/linux-core/drm_crtc_helper.c index a8c44b76..fcb1243c 100644 --- a/linux-core/drm_crtc_helper.c +++ b/linux-core/drm_crtc_helper.c @@ -662,7 +662,14 @@ bool drm_helper_initial_config(struct drm_device *dev, bool can_grow) */ list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - struct drm_crtc *crtc = connector->encoder->crtc; + struct drm_encoder *encoder = connector->encoder; + struct drm_crtc *crtc; + + if (!encoder) + continue; + + crtc = connector->encoder->crtc; + /* can't setup the connector if there's no assigned mode */ if (!crtc || !crtc->desired_mode) continue; -- cgit v1.2.3 From 76a44f14d6339e5bc0c936ef4a360f6c152511bd Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 4 Jun 2008 11:59:28 +1000 Subject: drm/modesetting: overhaul the fb create/delete. Move TTM code into the driver --- linux-core/drm_crtc_helper.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'linux-core/drm_crtc_helper.c') diff --git a/linux-core/drm_crtc_helper.c b/linux-core/drm_crtc_helper.c index fcb1243c..f35c0a49 100644 --- a/linux-core/drm_crtc_helper.c +++ b/linux-core/drm_crtc_helper.c @@ -749,3 +749,17 @@ int drm_helper_hotplug_stage_two(struct drm_device *dev, struct drm_connector *c } EXPORT_SYMBOL(drm_helper_hotplug_stage_two); + +int drm_helper_mode_fill_fb_struct(struct drm_framebuffer *fb, + struct drm_mode_fb_cmd *mode_cmd) +{ + fb->width = mode_cmd->width; + fb->height = mode_cmd->height; + fb->pitch = mode_cmd->pitch; + fb->bits_per_pixel = mode_cmd->bpp; + fb->depth = mode_cmd->depth; + fb->mm_handle = mode_cmd->handle; + + return 0; +} +EXPORT_SYMBOL(drm_helper_mode_fill_fb_struct); -- cgit v1.2.3 From fd27591c6cadd2a868f4110b8993a86c37837d3e Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 4 Jun 2008 13:00:31 +1000 Subject: drm/modesetting: pass object handle to driver !bo --- linux-core/drm_crtc_helper.c | 49 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 46 insertions(+), 3 deletions(-) (limited to 'linux-core/drm_crtc_helper.c') diff --git a/linux-core/drm_crtc_helper.c b/linux-core/drm_crtc_helper.c index f35c0a49..58d21b99 100644 --- a/linux-core/drm_crtc_helper.c +++ b/linux-core/drm_crtc_helper.c @@ -1,6 +1,4 @@ - -/* - * Copyright (c) 2006-2007 Intel Corporation +/* (c) 2006-2007 Intel Corporation * Copyright (c) 2007 Dave Airlie * * DRM core CRTC related functions @@ -763,3 +761,48 @@ int drm_helper_mode_fill_fb_struct(struct drm_framebuffer *fb, return 0; } EXPORT_SYMBOL(drm_helper_mode_fill_fb_struct); + +/** + * drm_get_buffer_object - find the buffer object for a given handle + * @dev: DRM device + * @bo: pointer to caller's buffer_object pointer + * @handle: handle to lookup + * + * LOCKING: + * Must take @dev's struct_mutex to protect buffer object lookup. + * + * Given @handle, lookup the buffer object in @dev and put it in the caller's + * @bo pointer. + * + * RETURNS: + * Zero on success, -EINVAL if the handle couldn't be found. + */ +int drm_get_buffer_object(struct drm_device *dev, struct drm_buffer_object **bo, unsigned long handle) +{ + struct drm_user_object *uo; + struct drm_hash_item *hash; + int ret; + + *bo = NULL; + + mutex_lock(&dev->struct_mutex); + ret = drm_ht_find_item(&dev->object_hash, handle, &hash); + if (ret) { + DRM_ERROR("Couldn't find handle.\n"); + ret = -EINVAL; + goto out_err; + } + + uo = drm_hash_entry(hash, struct drm_user_object, hash); + if (uo->type != drm_buffer_type) { + ret = -EINVAL; + goto out_err; + } + + *bo = drm_user_object_entry(uo, struct drm_buffer_object, base); + ret = 0; +out_err: + mutex_unlock(&dev->struct_mutex); + return ret; +} +EXPORT_SYMBOL(drm_get_buffer_object); -- cgit v1.2.3 From cf1964f971cc298ece91064953f7d00ed13e541d Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 4 Jun 2008 15:17:13 +1000 Subject: drm: fix hotplug oops --- linux-core/drm_crtc_helper.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) (limited to 'linux-core/drm_crtc_helper.c') diff --git a/linux-core/drm_crtc_helper.c b/linux-core/drm_crtc_helper.c index 58d21b99..4083d6b7 100644 --- a/linux-core/drm_crtc_helper.c +++ b/linux-core/drm_crtc_helper.c @@ -712,9 +712,11 @@ int drm_helper_hotplug_stage_two(struct drm_device *dev, struct drm_connector *c return 0; } - if (connector->encoder->crtc && connector->encoder->crtc->desired_mode) { - DRM_DEBUG("drm thinks that the connector already has a config\n"); - has_config = 1; + if (connector->encoder) { + if (connector->encoder->crtc && connector->encoder->crtc->desired_mode) { + DRM_DEBUG("drm thinks that the connector already has a config\n"); + has_config = 1; + } } drm_helper_probe_connector_modes(dev, 2048, 2048); @@ -722,6 +724,11 @@ int drm_helper_hotplug_stage_two(struct drm_device *dev, struct drm_connector *c if (!has_config) drm_pick_crtcs(dev); + if (!connector->encoder) { + DRM_DEBUG("could not find a desired mode or crtc for connector\n"); + return 1; + } + if (!connector->encoder->crtc || !connector->encoder->crtc->desired_mode) { DRM_DEBUG("could not find a desired mode or crtc for connector\n"); return 1; -- cgit v1.2.3 From 967bd219116a4f20aec828b890a225d2f92afd0b Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 5 Jun 2008 11:11:22 +1000 Subject: modesetting: initial attempt at debonging fb --- linux-core/drm_crtc_helper.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'linux-core/drm_crtc_helper.c') diff --git a/linux-core/drm_crtc_helper.c b/linux-core/drm_crtc_helper.c index 4083d6b7..3ff7e07e 100644 --- a/linux-core/drm_crtc_helper.c +++ b/linux-core/drm_crtc_helper.c @@ -643,15 +643,20 @@ EXPORT_SYMBOL(drm_crtc_helper_set_config); */ bool drm_helper_initial_config(struct drm_device *dev, bool can_grow) { - struct drm_connector *connector; int ret = false; mutex_lock(&dev->mode_config.mutex); - drm_helper_probe_connector_modes(dev, 2048, 2048); + drm_helper_probe_connector_modes(dev, dev->mode_config.max_width, dev->mode_config.max_height); drm_pick_crtcs(dev); + /* use all the info we have to setup the fb */ + dev->driver->fb_probe(dev); +#if 0 + /* have to do a driver pick here */ + /* get the lowest common denom of width height that will fit nicely - size the fb to this + size, however may need a wider stride for crtc alignment */ /* This is a little screwy, as we've already walked the connectors * 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 @@ -680,7 +685,7 @@ bool drm_helper_initial_config(struct drm_device *dev, bool can_grow) } drm_helper_disable_unused_functions(dev); - +#endif mutex_unlock(&dev->mode_config.mutex); return ret; } @@ -736,7 +741,7 @@ int drm_helper_hotplug_stage_two(struct drm_device *dev, struct drm_connector *c /* We should really check if there is a fb using this crtc */ if (!has_config) - dev->driver->fb_probe(dev, connector->encoder->crtc, connector); + dev->driver->fb_probe(dev); else { dev->driver->fb_resize(dev, connector->encoder->crtc); -- cgit v1.2.3 From f73e54bbf0b97a8f5184ede64d4f263020d623ee Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 5 Jun 2008 13:40:08 +1000 Subject: drm: modesetting unify the hotplug init paths a lot. remove fb callbacks, just probe into the driver to sort it out --- linux-core/drm_crtc_helper.c | 107 ++++++++----------------------------------- 1 file changed, 18 insertions(+), 89 deletions(-) (limited to 'linux-core/drm_crtc_helper.c') diff --git a/linux-core/drm_crtc_helper.c b/linux-core/drm_crtc_helper.c index 3ff7e07e..1b6118de 100644 --- a/linux-core/drm_crtc_helper.c +++ b/linux-core/drm_crtc_helper.c @@ -496,6 +496,7 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) crtc_funcs = set->crtc->helper_private; DRM_DEBUG("crtc: %p fb: %p connectors: %p num_connectors: %i (x, y) (%i, %i)\n", set->crtc, set->fb, set->connectors, set->num_connectors, set->x, set->y); + dev = set->crtc->dev; /* save previous config */ @@ -532,7 +533,7 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) list_for_each_entry(connector, &dev->mode_config.connector_list, head) { struct drm_connector_helper_funcs *connector_funcs = connector->helper_private; save_encoders[count++] = connector->encoder; - new_encoder = NULL; + new_encoder = connector->encoder; for (ro = 0; ro < set->num_connectors; ro++) { if (set->connectors[ro] == connector) { new_encoder = connector_funcs->best_encoder(connector); @@ -626,6 +627,20 @@ fail_no_encoder: } EXPORT_SYMBOL(drm_crtc_helper_set_config); +bool drm_helper_plugged_event(struct drm_device *dev) +{ + drm_helper_probe_connector_modes(dev, dev->mode_config.max_width, dev->mode_config.max_height); + + drm_pick_crtcs(dev); + + /* alert the driver fb layer */ + dev->mode_config.funcs->fb_changed(dev); + + drm_helper_disable_unused_functions(dev); + + drm_sysfs_hotplug_event(dev); + return true; +} /** * drm_initial_config - setup a sane initial connector configuration * @dev: DRM device @@ -645,48 +660,7 @@ bool drm_helper_initial_config(struct drm_device *dev, bool can_grow) { int ret = false; - mutex_lock(&dev->mode_config.mutex); - - drm_helper_probe_connector_modes(dev, dev->mode_config.max_width, dev->mode_config.max_height); - - drm_pick_crtcs(dev); - - /* use all the info we have to setup the fb */ - dev->driver->fb_probe(dev); -#if 0 - /* have to do a driver pick here */ - /* get the lowest common denom of width height that will fit nicely - size the fb to this - size, however may need a wider stride for crtc alignment */ - /* This is a little screwy, as we've already walked the connectors - * 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 connectors - * this fixes up their crtc's. - */ - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - - struct drm_encoder *encoder = connector->encoder; - struct drm_crtc *crtc; - - if (!encoder) - continue; - - crtc = connector->encoder->crtc; - - /* can't setup the connector if there's no assigned mode */ - if (!crtc || !crtc->desired_mode) - continue; - - dev->driver->fb_probe(dev, crtc, connector); - - /* and needs an attached fb */ - if (crtc->fb) - drm_crtc_helper_set_mode(crtc, crtc->desired_mode, 0, 0); - } - - drm_helper_disable_unused_functions(dev); -#endif - mutex_unlock(&dev->mode_config.mutex); + drm_helper_plugged_event(dev); return ret; } EXPORT_SYMBOL(drm_helper_initial_config); @@ -707,59 +681,14 @@ EXPORT_SYMBOL(drm_helper_initial_config); int drm_helper_hotplug_stage_two(struct drm_device *dev, struct drm_connector *connector, 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 (connector->encoder) { - if (connector->encoder->crtc && connector->encoder->crtc->desired_mode) { - DRM_DEBUG("drm thinks that the connector already has a config\n"); - has_config = 1; - } - } - - drm_helper_probe_connector_modes(dev, 2048, 2048); - - if (!has_config) - drm_pick_crtcs(dev); - - if (!connector->encoder) { - DRM_DEBUG("could not find a desired mode or crtc for connector\n"); - return 1; - } - - if (!connector->encoder->crtc || !connector->encoder->crtc->desired_mode) { - DRM_DEBUG("could not find a desired mode or crtc for connector\n"); - return 1; - } - - /* We should really check if there is a fb using this crtc */ - if (!has_config) - dev->driver->fb_probe(dev); - else { - dev->driver->fb_resize(dev, connector->encoder->crtc); - -#if 0 - if (!drm_crtc_set_mode(connector->encoder->crtc, connector->encoder->crtc->desired_mode, 0, 0)) - DRM_ERROR("failed to set mode after hotplug\n"); -#endif - } - - drm_sysfs_hotplug_event(dev); - - drm_helper_disable_unused_functions(dev); + drm_helper_plugged_event(dev); return 0; } EXPORT_SYMBOL(drm_helper_hotplug_stage_two); - int drm_helper_mode_fill_fb_struct(struct drm_framebuffer *fb, struct drm_mode_fb_cmd *mode_cmd) { -- cgit v1.2.3 From d9ead89c79732124f54b4a9dfe698bc7aad7faee Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 5 Jun 2008 16:32:41 +1000 Subject: drm/modeset: add more debugging and fixup some fb enable/disabe bits --- linux-core/drm_crtc_helper.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) (limited to 'linux-core/drm_crtc_helper.c') diff --git a/linux-core/drm_crtc_helper.c b/linux-core/drm_crtc_helper.c index 1b6118de..edb739f5 100644 --- a/linux-core/drm_crtc_helper.c +++ b/linux-core/drm_crtc_helper.c @@ -67,6 +67,7 @@ void drm_helper_probe_single_connector_modes(struct drm_connector *connector, ui struct drm_connector_helper_funcs *connector_funcs = connector->helper_private; int ret; + DRM_DEBUG("%s\n", drm_get_connector_name(connector)); /* set all modes to the unverified state */ list_for_each_entry_safe(mode, t, &connector->modes, head) mode->status = MODE_UNVERIFIED; @@ -186,8 +187,11 @@ void drm_helper_disable_unused_functions(struct drm_device *dev) list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; - if (!crtc->enabled) + crtc->enabled = drm_helper_crtc_in_use(crtc); + if (!crtc->enabled) { crtc_funcs->dpms(crtc, DPMSModeOff); + crtc->fb = NULL; + } } } EXPORT_SYMBOL(drm_helper_disable_unused_functions); @@ -209,6 +213,7 @@ static void drm_pick_crtcs (struct drm_device *dev) struct drm_connector_helper_funcs *connector_funcs; int found; + DRM_DEBUG("\n"); /* clean out all the encoder/crtc combos */ list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { encoder->crtc = NULL; @@ -515,8 +520,13 @@ 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) - flip_or_move = true; + if (set->crtc->fb != set->fb) { + /* if we have no fb then its a change not a flip */ + if (set->crtc->fb == NULL) + changed = true; + else + flip_or_move = true; + } if (set->x != set->crtc->x || set->y != set->crtc->y) flip_or_move = true; @@ -629,6 +639,8 @@ EXPORT_SYMBOL(drm_crtc_helper_set_config); bool drm_helper_plugged_event(struct drm_device *dev) { + DRM_DEBUG("\n"); + drm_helper_probe_connector_modes(dev, dev->mode_config.max_width, dev->mode_config.max_height); drm_pick_crtcs(dev); -- cgit v1.2.3 From 25c1bb334f3a32e3e635e9d5de1abf8abdcc87f0 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 6 Jun 2008 10:38:35 +1000 Subject: drm/intel: make hotplug just be an event --- linux-core/drm_crtc_helper.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'linux-core/drm_crtc_helper.c') diff --git a/linux-core/drm_crtc_helper.c b/linux-core/drm_crtc_helper.c index edb739f5..777820d7 100644 --- a/linux-core/drm_crtc_helper.c +++ b/linux-core/drm_crtc_helper.c @@ -690,8 +690,7 @@ EXPORT_SYMBOL(drm_helper_initial_config); * RETURNS: * Zero on success, errno on failure. */ -int drm_helper_hotplug_stage_two(struct drm_device *dev, struct drm_connector *connector, - bool connected) +int drm_helper_hotplug_stage_two(struct drm_device *dev) { dev->mode_config.hotplug_counter++; -- cgit v1.2.3 From 6d4ffd12cd8d3713067adf5fa3bdcb023b0745f1 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 6 Jun 2008 16:24:27 +1000 Subject: drm: fix up fb resize again --- linux-core/drm_crtc_helper.c | 1 + 1 file changed, 1 insertion(+) (limited to 'linux-core/drm_crtc_helper.c') diff --git a/linux-core/drm_crtc_helper.c b/linux-core/drm_crtc_helper.c index 777820d7..bfddab99 100644 --- a/linux-core/drm_crtc_helper.c +++ b/linux-core/drm_crtc_helper.c @@ -758,3 +758,4 @@ out_err: return ret; } EXPORT_SYMBOL(drm_get_buffer_object); + -- cgit v1.2.3 From e810cb9243fe6c4905182869d9e3272d861a14cb Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Sun, 6 Jul 2008 10:52:25 +0200 Subject: modesetting-101: rename modeflags, as to avoid conflicts with the xorg definitions --- linux-core/drm_crtc_helper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'linux-core/drm_crtc_helper.c') diff --git a/linux-core/drm_crtc_helper.c b/linux-core/drm_crtc_helper.c index bfddab99..d5a9f279 100644 --- a/linux-core/drm_crtc_helper.c +++ b/linux-core/drm_crtc_helper.c @@ -38,7 +38,7 @@ static struct drm_display_mode std_mode[] = { { DRM_MODE("640x480", DRM_MODE_TYPE_DEFAULT, 25200, 640, 656, 752, 800, 0, 480, 490, 492, 525, 0, - V_NHSYNC | V_NVSYNC) }, /* 640x480@60Hz */ + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 640x480@60Hz */ }; /** -- cgit v1.2.3 From 6738e7b00bf05529303ed690873495db6d83337c Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Sun, 6 Jul 2008 11:08:49 +0200 Subject: modesetting-101: Rename DPMS modes to avoid compatibility issues with xorg definitions. --- linux-core/drm_crtc_helper.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'linux-core/drm_crtc_helper.c') diff --git a/linux-core/drm_crtc_helper.c b/linux-core/drm_crtc_helper.c index d5a9f279..18fc9d98 100644 --- a/linux-core/drm_crtc_helper.c +++ b/linux-core/drm_crtc_helper.c @@ -182,14 +182,14 @@ void drm_helper_disable_unused_functions(struct drm_device *dev) list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { encoder_funcs = encoder->helper_private; if (!encoder->crtc) - (*encoder_funcs->dpms)(encoder, DPMSModeOff); + (*encoder_funcs->dpms)(encoder, DRM_MODE_DPMS_OFF); } list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; crtc->enabled = drm_helper_crtc_in_use(crtc); if (!crtc->enabled) { - crtc_funcs->dpms(crtc, DPMSModeOff); + crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF); crtc->fb = NULL; } } -- cgit v1.2.3 From 7fd8a5de63781f6faa053509c80e02e8f1cdbb69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20H=C3=B8gsberg?= Date: Mon, 7 Jul 2008 11:56:59 -0400 Subject: Use lowercase bool constants. --- linux-core/drm_crtc_helper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'linux-core/drm_crtc_helper.c') diff --git a/linux-core/drm_crtc_helper.c b/linux-core/drm_crtc_helper.c index bfddab99..ffd20342 100644 --- a/linux-core/drm_crtc_helper.c +++ b/linux-core/drm_crtc_helper.c @@ -95,7 +95,7 @@ void drm_helper_probe_single_connector_modes(struct drm_connector *connector, ui } - drm_mode_prune_invalid(dev, &connector->modes, TRUE); + drm_mode_prune_invalid(dev, &connector->modes, true); if (list_empty(&connector->modes)) { struct drm_display_mode *stdmode; -- cgit v1.2.3 From a9089c45570c7b2df9155c2cd73aeea59cc0e34e Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Sat, 12 Jul 2008 16:32:09 +1000 Subject: modesetting/helper: fix array overrun - count should be reset here --- linux-core/drm_crtc_helper.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'linux-core/drm_crtc_helper.c') diff --git a/linux-core/drm_crtc_helper.c b/linux-core/drm_crtc_helper.c index 18fc9d98..ec76aa93 100644 --- a/linux-core/drm_crtc_helper.c +++ b/linux-core/drm_crtc_helper.c @@ -566,7 +566,8 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) ret = -EINVAL; goto fail_no_encoder; } - + + count = 0; list_for_each_entry(connector, &dev->mode_config.connector_list, head) { if (!connector->encoder) continue; -- cgit v1.2.3 From df9871064e8b564d9ae2e56d561b64434fd004af Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Sat, 26 Jul 2008 08:56:23 +1000 Subject: radeon: add initial atombios modesetting and GEM -> TTM translation layer. This is an initial import of the atom bios parser with modesetting support for r500 hw using atombios. It also includes a simple memory manager layer that translates a radeon GEM style interface onto TTM internally. So far this memory manager has only been used for pinned object allocation for the DDX to test modesetting. --- linux-core/drm_crtc_helper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'linux-core/drm_crtc_helper.c') diff --git a/linux-core/drm_crtc_helper.c b/linux-core/drm_crtc_helper.c index 6f16dad6..e0d93606 100644 --- a/linux-core/drm_crtc_helper.c +++ b/linux-core/drm_crtc_helper.c @@ -500,7 +500,7 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) crtc_funcs = set->crtc->helper_private; - DRM_DEBUG("crtc: %p fb: %p connectors: %p num_connectors: %i (x, y) (%i, %i)\n", set->crtc, set->fb, set->connectors, set->num_connectors, set->x, set->y); + DRM_DEBUG("crtc: %p %d fb: %p connectors: %p num_connectors: %i (x, y) (%i, %i)\n", set->crtc, set->crtc->base.id, set->fb, set->connectors, set->num_connectors, set->x, set->y); dev = set->crtc->dev; -- cgit v1.2.3 From 9b8d71b5eb09857b07409731d3de182751f712a2 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 31 Jul 2008 12:54:48 +1000 Subject: TTM: remove API and userspace objects. This removes all the TTM userspace API and all userspace objects. It also removes the drm_bo_lock.c code --- linux-core/drm_crtc_helper.c | 44 -------------------------------------------- 1 file changed, 44 deletions(-) (limited to 'linux-core/drm_crtc_helper.c') diff --git a/linux-core/drm_crtc_helper.c b/linux-core/drm_crtc_helper.c index e0d93606..ee1dc258 100644 --- a/linux-core/drm_crtc_helper.c +++ b/linux-core/drm_crtc_helper.c @@ -715,48 +715,4 @@ int drm_helper_mode_fill_fb_struct(struct drm_framebuffer *fb, } EXPORT_SYMBOL(drm_helper_mode_fill_fb_struct); -/** - * drm_get_buffer_object - find the buffer object for a given handle - * @dev: DRM device - * @bo: pointer to caller's buffer_object pointer - * @handle: handle to lookup - * - * LOCKING: - * Must take @dev's struct_mutex to protect buffer object lookup. - * - * Given @handle, lookup the buffer object in @dev and put it in the caller's - * @bo pointer. - * - * RETURNS: - * Zero on success, -EINVAL if the handle couldn't be found. - */ -int drm_get_buffer_object(struct drm_device *dev, struct drm_buffer_object **bo, unsigned long handle) -{ - struct drm_user_object *uo; - struct drm_hash_item *hash; - int ret; - - *bo = NULL; - - mutex_lock(&dev->struct_mutex); - ret = drm_ht_find_item(&dev->object_hash, handle, &hash); - if (ret) { - DRM_ERROR("Couldn't find handle.\n"); - ret = -EINVAL; - goto out_err; - } - - uo = drm_hash_entry(hash, struct drm_user_object, hash); - if (uo->type != drm_buffer_type) { - ret = -EINVAL; - goto out_err; - } - - *bo = drm_user_object_entry(uo, struct drm_buffer_object, base); - ret = 0; -out_err: - mutex_unlock(&dev->struct_mutex); - return ret; -} -EXPORT_SYMBOL(drm_get_buffer_object); -- cgit v1.2.3 From 129c8a11814741a997e3d039ab4be542d38e5ed8 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 4 Aug 2008 14:53:14 +1000 Subject: modesetting: pick_crtcs can't be static --- linux-core/drm_crtc_helper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'linux-core/drm_crtc_helper.c') diff --git a/linux-core/drm_crtc_helper.c b/linux-core/drm_crtc_helper.c index ee1dc258..dc18dbb4 100644 --- a/linux-core/drm_crtc_helper.c +++ b/linux-core/drm_crtc_helper.c @@ -203,7 +203,7 @@ EXPORT_SYMBOL(drm_helper_disable_unused_functions); * LOCKING: * Caller must hold mode config lock. */ -static void drm_pick_crtcs (struct drm_device *dev) +void drm_pick_crtcs (struct drm_device *dev) { int c, o, assigned; struct drm_connector *connector, *connector_equal; -- cgit v1.2.3 From 23cb67dfbabe8c76ffd86b6c01abacc027d0fb72 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 28 Aug 2008 16:18:09 +1000 Subject: drm: port X crtc picking algorithm. This mimics the X.org from ajax with less options --- linux-core/drm_crtc_helper.c | 294 ++++++++++++++++++++++++++----------------- 1 file changed, 182 insertions(+), 112 deletions(-) (limited to 'linux-core/drm_crtc_helper.c') diff --git a/linux-core/drm_crtc_helper.c b/linux-core/drm_crtc_helper.c index dc18dbb4..89d87a6c 100644 --- a/linux-core/drm_crtc_helper.c +++ b/linux-core/drm_crtc_helper.c @@ -196,139 +196,209 @@ void drm_helper_disable_unused_functions(struct drm_device *dev) } EXPORT_SYMBOL(drm_helper_disable_unused_functions); -/** - * drm_pick_crtcs - pick crtcs for connector devices - * @dev: DRM device - * - * LOCKING: - * Caller must hold mode config lock. - */ -void drm_pick_crtcs (struct drm_device *dev) +static struct drm_display_mode *drm_has_preferred_mode(struct drm_connector *connector, int width, int height) { - int c, o, assigned; - struct drm_connector *connector, *connector_equal; - struct drm_encoder *encoder, *encoder_equal; - struct drm_crtc *crtc; - struct drm_display_mode *des_mode = NULL, *modes, *modes_equal; - struct drm_connector_helper_funcs *connector_funcs; - int found; + struct drm_display_mode *mode; - DRM_DEBUG("\n"); - /* clean out all the encoder/crtc combos */ - list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { - encoder->crtc = NULL; + list_for_each_entry(mode, &connector->modes, head) { + if (drm_mode_width(mode) > width || + drm_mode_height(mode) > height) + continue; + if (mode->type & DRM_MODE_TYPE_PREFERRED) + return mode; + } + return NULL; +} + +static bool drm_connector_enabled(struct drm_connector *connector, bool strict) +{ + bool enable; + + if (strict) { + enable = connector->status == connector_status_connected; + } else { + enable = connector->status != connector_status_disconnected; + } + return enable; +} + +static void drm_enable_connectors(struct drm_device *dev, bool *enabled) +{ + bool any_enabled = false; + struct drm_connector *connector; + int i = 0; + + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + any_enabled |= enabled[i] = drm_connector_enabled(connector, true); + i++; + } + + if (!any_enabled) { + i = 0; + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + enabled[i] = drm_connector_enabled(connector, false); + i++; + } } +} + +static bool drm_target_preferred(struct drm_device *dev, struct drm_display_mode **modes, + bool *enabled, int width, int height) +{ + struct drm_connector *connector; + struct drm_display_mode *preferred; + int i = 0; list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - connector_funcs = connector->helper_private; - connector->encoder = NULL; - - /* Don't hook up connectors 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 connectors now, then we only create - * /dev/fbX for the connector that's enabled, that's good as - * the users console will be on that connector. - * - * If we do hook up connectors 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 connector. Ugh. - */ - if (connector->status != connector_status_connected) - continue; - if (list_empty(&connector->modes)) + if (enabled[i] == false) { + i++; continue; - - des_mode = NULL; - found = 0; - list_for_each_entry(des_mode, &connector->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, &connector->modes, head) { + modes[i] = drm_has_preferred_mode(connector, width, height); + if (!modes[i]) { + list_for_each_entry(modes[i], &connector->modes, head) break; - } } + i++; + } + return true; +} - encoder = connector_funcs->best_encoder(connector); - if (!encoder) - continue; +static int drm_pick_crtcs(struct drm_device *dev, + struct drm_crtc **best_crtcs, + struct drm_display_mode **modes, + int n, int width, int height) +{ + int c, o; + struct drm_connector *connector; + struct drm_connector_helper_funcs *connector_funcs; + struct drm_encoder *encoder; + struct drm_crtc *best_crtc; + int my_score, best_score, score; + struct drm_crtc **crtcs, *crtc; + + if (n == dev->mode_config.num_connector) + return 0; + c = 0; + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + if (c == n) + break; + c++; + } - connector->encoder = encoder; + best_crtcs[n] = NULL; + best_crtc = NULL; + best_score = drm_pick_crtcs(dev, best_crtcs, modes, n+1, width, height); + if (modes[n] == NULL) { + return best_score; + } - c = -1; - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - assigned = 0; + crtcs = kmalloc(dev->mode_config.num_connector * sizeof(struct drm_crtc *), GFP_KERNEL); + if (!crtcs) + return best_score; + + my_score = 1; + if (connector->status == connector_status_connected) + my_score++; + if (drm_has_preferred_mode(connector, width, height)) + my_score++; + + connector_funcs = connector->helper_private; + encoder = connector_funcs->best_encoder(connector); + if (!encoder) + goto out; + + connector->encoder = encoder; + + /* select a crtc for this connector and then attempt to configure + remaining connectors */ + c = 0; + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + if ((connector->encoder->possible_crtcs & (1 << c)) == 0) { c++; - if ((encoder->possible_crtcs & (1 << c)) == 0) - continue; - - list_for_each_entry(encoder_equal, &dev->mode_config.encoder_list, head) { - if (encoder->base.id == encoder_equal->base.id) - continue; + continue; + } - /* Find out if crtc has been assigned before */ - if (encoder_equal->crtc == crtc) - assigned = 1; - } + for (o = 0; o < n; o++) + if (best_crtcs[o] == crtc) + break; -#if 1 /* continue for now */ - if (assigned) - continue; -#endif - - o = -1; - list_for_each_entry(connector_equal, &dev->mode_config.connector_list, head) { - o++; - if (connector->base.id == connector_equal->base.id) - continue; - - encoder_equal = connector_equal->encoder; - - if (!encoder_equal) - continue; - - list_for_each_entry(modes, &connector->modes, head) { - list_for_each_entry(modes_equal, &connector_equal->modes, head) { - if (drm_mode_equal (modes, modes_equal)) { - if ((encoder->possible_clones & encoder_equal->possible_clones) && (connector_equal->encoder->crtc == crtc)) { - printk("Cloning %s (0x%x) to %s (0x%x)\n",drm_get_connector_name(connector),encoder->possible_clones,drm_get_connector_name(connector_equal),encoder_equal->possible_clones); - des_mode = modes; - assigned = 0; - goto clone; - } - } - } - } - } + if (o < n) { + /* ignore cloning for now */ + c++; + continue; + } -clone: - /* crtc has been assigned skip it */ - if (assigned) - continue; - - /* Found a CRTC to attach to, do it ! */ - encoder->crtc = crtc; - encoder->crtc->desired_mode = des_mode; - connector->initial_x = 0; - connector->initial_y = 0; - DRM_DEBUG("Desired mode for CRTC %d is 0x%x:%s\n",c,des_mode->base.id, des_mode->name); - break; - } + crtcs[n] = crtc; + memcpy(crtcs, best_crtcs, n * sizeof(struct drm_crtc *)); + score = my_score + drm_pick_crtcs(dev, crtcs, modes, n + 1, width, height); + if (score > best_score) { + best_crtc = crtc; + best_score = score; + memcpy(best_crtcs, crtcs, dev->mode_config.num_connector * sizeof(struct drm_crtc *)); + } + c++; } +out: + kfree(crtcs); + return best_score; } -EXPORT_SYMBOL(drm_pick_crtcs); +static void drm_setup_crtcs(struct drm_device *dev) +{ + struct drm_crtc **crtcs; + struct drm_display_mode **modes; + struct drm_encoder *encoder; + struct drm_connector *connector; + bool *enabled; + int width, height; + int i, ret; + + width = dev->mode_config.max_width; + height = dev->mode_config.max_height; + + /* clean out all the encoder/crtc combos */ + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + encoder->crtc = NULL; + } + + crtcs = kcalloc(dev->mode_config.num_connector, sizeof(struct drm_crtc *), GFP_KERNEL); + modes = kcalloc(dev->mode_config.num_connector, sizeof(struct drm_display_mode *), GFP_KERNEL); + enabled = kcalloc(dev->mode_config.num_connector, sizeof(bool), GFP_KERNEL); + + drm_enable_connectors(dev, enabled); + + ret = drm_target_preferred(dev, modes, enabled, width, height); + if (!ret) + DRM_ERROR("Unable to find initial modes\n"); + + drm_pick_crtcs(dev, crtcs, modes, 0, width, height); + + i = 0; + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + struct drm_display_mode *mode = modes[i]; + struct drm_crtc *crtc = crtcs[i]; + + if (connector->encoder == NULL) { + i++; + continue; + } + + if (mode && crtc) { + crtc->desired_mode = mode; + connector->encoder->crtc = crtc; + } else + connector->encoder->crtc = NULL; + i++; + } + + kfree(crtcs); + kfree(modes); + kfree(enabled); +} /** * drm_crtc_set_mode - set a mode * @crtc: CRTC to program @@ -644,7 +714,7 @@ bool drm_helper_plugged_event(struct drm_device *dev) drm_helper_probe_connector_modes(dev, dev->mode_config.max_width, dev->mode_config.max_height); - drm_pick_crtcs(dev); + drm_setup_crtcs(dev); /* alert the driver fb layer */ dev->mode_config.funcs->fb_changed(dev); -- cgit v1.2.3 From 1062d8dcff19ded743f046e27adb889f3596ab4d Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 18 Sep 2008 09:59:08 +1000 Subject: modesetting: Add helper to force restore modes on crtcs at resume time --- linux-core/drm_crtc_helper.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'linux-core/drm_crtc_helper.c') diff --git a/linux-core/drm_crtc_helper.c b/linux-core/drm_crtc_helper.c index 89d87a6c..71bdc447 100644 --- a/linux-core/drm_crtc_helper.c +++ b/linux-core/drm_crtc_helper.c @@ -785,4 +785,22 @@ int drm_helper_mode_fill_fb_struct(struct drm_framebuffer *fb, } EXPORT_SYMBOL(drm_helper_mode_fill_fb_struct); +int drm_helper_resume_force_mode(struct drm_device *dev) +{ + struct drm_crtc *crtc; + int ret; + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + + if (!crtc->enabled) + continue; + + ret = drm_crtc_helper_set_mode(crtc, &crtc->mode, crtc->x, + crtc->y); + + if (ret == false) + DRM_ERROR("failed to set mode on crtc %p\n", crtc); + } + return 0; +} +EXPORT_SYMBOL(drm_helper_resume_force_mode); -- cgit v1.2.3 From a2216491c619082ad9a01bc949648834dc5a0d2f Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 28 Aug 2008 21:20:19 +1000 Subject: drm: fix brace placement --- linux-core/drm_crtc_helper.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'linux-core/drm_crtc_helper.c') diff --git a/linux-core/drm_crtc_helper.c b/linux-core/drm_crtc_helper.c index 71bdc447..b5073155 100644 --- a/linux-core/drm_crtc_helper.c +++ b/linux-core/drm_crtc_helper.c @@ -291,9 +291,8 @@ static int drm_pick_crtcs(struct drm_device *dev, best_crtcs[n] = NULL; best_crtc = NULL; best_score = drm_pick_crtcs(dev, best_crtcs, modes, n+1, width, height); - if (modes[n] == NULL) { + if (modes[n] == NULL) return best_score; - } crtcs = kmalloc(dev->mode_config.num_connector * sizeof(struct drm_crtc *), GFP_KERNEL); if (!crtcs) -- cgit v1.2.3 From 5fdfbee22acb8eaaa834457c30e6f68883ab1353 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20H=C3=B8gsberg?= Date: Tue, 23 Sep 2008 16:47:34 +1000 Subject: Store the buffer object backing the fb as a void pointer, not a handle. This lets us defer handle creation until userspace acutally asks for one, at which point we also have a drm_file to associate it with. --- linux-core/drm_crtc_helper.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'linux-core/drm_crtc_helper.c') diff --git a/linux-core/drm_crtc_helper.c b/linux-core/drm_crtc_helper.c index b5073155..b334f5b5 100644 --- a/linux-core/drm_crtc_helper.c +++ b/linux-core/drm_crtc_helper.c @@ -771,14 +771,15 @@ int drm_helper_hotplug_stage_two(struct drm_device *dev) EXPORT_SYMBOL(drm_helper_hotplug_stage_two); int drm_helper_mode_fill_fb_struct(struct drm_framebuffer *fb, - struct drm_mode_fb_cmd *mode_cmd) + struct drm_mode_fb_cmd *mode_cmd, + void *mm_private) { fb->width = mode_cmd->width; fb->height = mode_cmd->height; fb->pitch = mode_cmd->pitch; fb->bits_per_pixel = mode_cmd->bpp; fb->depth = mode_cmd->depth; - fb->mm_handle = mode_cmd->handle; + fb->mm_private = mm_private; return 0; } -- cgit v1.2.3 From 563e7e5930a8d628b33cb1f7a9aaea251f2fc50b Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 3 Nov 2008 09:36:03 +1000 Subject: radeon/drm: fixup ref counting in on fb objs --- linux-core/drm_crtc_helper.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'linux-core/drm_crtc_helper.c') diff --git a/linux-core/drm_crtc_helper.c b/linux-core/drm_crtc_helper.c index b334f5b5..776a98e1 100644 --- a/linux-core/drm_crtc_helper.c +++ b/linux-core/drm_crtc_helper.c @@ -771,15 +771,13 @@ int drm_helper_hotplug_stage_two(struct drm_device *dev) EXPORT_SYMBOL(drm_helper_hotplug_stage_two); int drm_helper_mode_fill_fb_struct(struct drm_framebuffer *fb, - struct drm_mode_fb_cmd *mode_cmd, - void *mm_private) + struct drm_mode_fb_cmd *mode_cmd) { fb->width = mode_cmd->width; fb->height = mode_cmd->height; fb->pitch = mode_cmd->pitch; fb->bits_per_pixel = mode_cmd->bpp; fb->depth = mode_cmd->depth; - fb->mm_private = mm_private; return 0; } -- cgit v1.2.3 From b1cf46378a54230291ba9fdb4dbbd4bc4befe049 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 10 Nov 2008 15:35:16 +1000 Subject: modesetting: set the crtc x,y after the mode base change --- linux-core/drm_crtc_helper.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'linux-core/drm_crtc_helper.c') diff --git a/linux-core/drm_crtc_helper.c b/linux-core/drm_crtc_helper.c index 776a98e1..58163e51 100644 --- a/linux-core/drm_crtc_helper.c +++ b/linux-core/drm_crtc_helper.c @@ -683,6 +683,8 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) if (set->crtc->fb != set->fb) set->crtc->fb = set->fb; crtc_funcs->mode_set_base(set->crtc, set->x, set->y); + set->crtc->x = set->x; + set->crtc->y = set->y; } kfree(save_encoders); -- cgit v1.2.3 From 195cc0d817f99e25a1e961deeabbb15a40b789ed Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 10 Nov 2008 15:37:16 +1000 Subject: drm/radeon: add dpms connector functions --- linux-core/drm_crtc_helper.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) (limited to 'linux-core/drm_crtc_helper.c') diff --git a/linux-core/drm_crtc_helper.c b/linux-core/drm_crtc_helper.c index 58163e51..ebb44794 100644 --- a/linux-core/drm_crtc_helper.c +++ b/linux-core/drm_crtc_helper.c @@ -804,3 +804,30 @@ int drm_helper_resume_force_mode(struct drm_device *dev) return 0; } EXPORT_SYMBOL(drm_helper_resume_force_mode); + +void drm_helper_set_connector_dpms(struct drm_connector *connector, + int dpms_mode) +{ + int i = 0; + struct drm_encoder *encoder; + struct drm_encoder_helper_funcs *encoder_funcs; + struct drm_mode_object *obj; + + for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { + if (connector->encoder_ids[i] == 0) + break; + + obj = drm_mode_object_find(connector->dev, + connector->encoder_ids[i], + DRM_MODE_OBJECT_ENCODER); + if (!obj) + continue; + + encoder = obj_to_encoder(obj); + encoder_funcs = encoder->helper_private; + if (encoder_funcs->dpms) + encoder_funcs->dpms(encoder, dpms_mode); + + } +} +EXPORT_SYMBOL(drm_helper_set_connector_dpms); -- cgit v1.2.3