diff options
author | Dave Airlie <airlied@redhat.com> | 2008-05-29 14:02:14 +1000 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2008-05-29 14:02:14 +1000 |
commit | df8cd54286fbae5903d8ede390ec4a11cb6c4b6c (patch) | |
tree | 915a1b55354bbd6e2f32f68ecd4d1fde8fb5cae6 | |
parent | ee5afc63428488c9c39e5ecd7d8cdc646a7b65b7 (diff) |
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.
-rw-r--r-- | linux-core/Makefile.kernel | 2 | ||||
-rw-r--r-- | linux-core/drm_crtc.c | 471 | ||||
-rw-r--r-- | linux-core/drm_crtc.h | 43 | ||||
-rw-r--r-- | linux-core/drm_crtc_helper.c | 515 | ||||
-rw-r--r-- | linux-core/drm_crtc_helper.h | 69 | ||||
-rw-r--r-- | linux-core/intel_crt.c | 17 | ||||
-rw-r--r-- | linux-core/intel_display.c | 29 | ||||
-rw-r--r-- | linux-core/intel_drv.h | 1 | ||||
-rw-r--r-- | linux-core/intel_dvo.c | 15 | ||||
-rw-r--r-- | linux-core/intel_fb.c | 6 | ||||
-rw-r--r-- | linux-core/intel_lvds.c | 16 | ||||
-rw-r--r-- | linux-core/intel_sdvo.c | 16 | ||||
-rw-r--r-- | linux-core/intel_tv.c | 12 | ||||
-rw-r--r-- | shared-core/i915_init.c | 3 | ||||
-rw-r--r-- | shared-core/i915_irq.c | 11 |
15 files changed, 688 insertions, 538 deletions
diff --git a/linux-core/Makefile.kernel b/linux-core/Makefile.kernel index f77f8642..ac9baf02 100644 --- a/linux-core/Makefile.kernel +++ b/linux-core/Makefile.kernel @@ -15,7 +15,7 @@ drm-objs := drm_auth.o drm_bufs.o drm_context.o drm_dma.o drm_drawable.o \ drm_hashtab.o drm_mm.o drm_object.o drm_compat.o \ drm_fence.o drm_ttm.o drm_bo.o drm_bo_move.o drm_crtc.o \ drm_edid.o drm_modes.o drm_bo_lock.o drm_regman.o \ - drm_vm_nopage_compat.o + drm_vm_nopage_compat.o drm_crtc_helper.o tdfx-objs := tdfx_drv.o r128-objs := r128_drv.o r128_cce.o r128_state.o r128_irq.o mga-objs := mga_drv.o mga_dma.o mga_state.o mga_warp.o mga_irq.o diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index e05466ee..a4a51080 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -418,133 +418,6 @@ void drm_crtc_probe_output_modes(struct drm_device *dev, int maxX, int maxY) } EXPORT_SYMBOL(drm_crtc_probe_output_modes); -/** - * drm_crtc_set_mode - set a mode - * @crtc: CRTC to program - * @mode: mode to use - * @x: width of mode - * @y: height of mode - * - * LOCKING: - * Caller must hold mode config lock. - * - * Try to set @mode on @crtc. Give @crtc and its associated outputs a chance - * to fixup or reject the mode prior to trying to set it. - * - * RETURNS: - * True if the mode was set successfully, or false otherwise. - */ -bool drm_crtc_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode, - int x, int y) -{ - struct drm_device *dev = crtc->dev; - struct drm_display_mode *adjusted_mode, saved_mode; - int saved_x, saved_y; - struct drm_output *output; - bool ret = true; - - adjusted_mode = drm_mode_duplicate(dev, mode); - - crtc->enabled = drm_crtc_in_use(crtc); - - if (!crtc->enabled) - return true; - - saved_mode = crtc->mode; - saved_x = crtc->x; - saved_y = crtc->y; - - /* Update crtc values up front so the driver can rely on them for mode - * setting. - */ - crtc->mode = *mode; - crtc->x = x; - crtc->y = y; - - if (drm_mode_equal(&saved_mode, &crtc->mode)) { - if (saved_x != crtc->x || saved_y != crtc->y) { - crtc->funcs->mode_set_base(crtc, crtc->x, crtc->y); - goto done; - } - } - - /* Pass our mode to the outputs and the CRTC to give them a chance to - * adjust it according to limitations or output properties, and also - * a chance to reject the mode entirely. - */ - list_for_each_entry(output, &dev->mode_config.output_list, head) { - - if (output->crtc != crtc) - continue; - - if (!(ret = output->funcs->mode_fixup(output, mode, adjusted_mode))) { - goto done; - } - } - - if (!(ret = crtc->funcs->mode_fixup(crtc, mode, adjusted_mode))) { - goto done; - } - - /* Prepare the outputs and CRTCs before setting the mode. */ - list_for_each_entry(output, &dev->mode_config.output_list, head) { - - if (output->crtc != crtc) - continue; - - /* Disable the output as the first thing we do. */ - output->funcs->prepare(output); - } - - crtc->funcs->prepare(crtc); - - /* Set up the DPLL and any output state that needs to adjust or depend - * on the DPLL. - */ - crtc->funcs->mode_set(crtc, mode, adjusted_mode, x, y); - - list_for_each_entry(output, &dev->mode_config.output_list, head) { - - if (output->crtc != crtc) - continue; - - DRM_INFO("%s: set mode %s %x\n", drm_get_output_name(output), mode->name, mode->mode_id); - - output->funcs->mode_set(output, mode, adjusted_mode); - } - - /* Now, enable the clocks, plane, pipe, and outputs that we set up. */ - crtc->funcs->commit(crtc); - - list_for_each_entry(output, &dev->mode_config.output_list, head) { - - if (output->crtc != crtc) - continue; - - output->funcs->commit(output); - -#if 0 // TODO def RANDR_12_INTERFACE - if (output->randr_output) - RRPostPendingProperties (output->randr_output); -#endif - } - - /* XXX free adjustedmode */ - drm_mode_destroy(dev, adjusted_mode); - /* TODO */ -// if (scrn->pScreen) -// drm_crtc_set_screen_sub_pixel_order(dev); - -done: - if (!ret) { - crtc->mode = saved_mode; - crtc->x = saved_x; - crtc->y = saved_y; - } - - return ret; -} -EXPORT_SYMBOL(drm_crtc_set_mode); /** * drm_disable_unused_functions - disable unused objects @@ -896,171 +769,8 @@ out_err: return ret; } -/** - * drm_pick_crtcs - pick crtcs for output devices - * @dev: DRM device - * - * LOCKING: - * Caller must hold mode config lock. - */ -static void drm_pick_crtcs (struct drm_device *dev) -{ - int c, o, assigned; - struct drm_output *output, *output_equal; - struct drm_crtc *crtc; - struct drm_display_mode *des_mode = NULL, *modes, *modes_equal; - int found; - - list_for_each_entry(output, &dev->mode_config.output_list, head) { - output->crtc = NULL; - - /* Don't hook up outputs that are disconnected ?? - * - * This is debateable. Do we want fixed /dev/fbX or - * dynamic on hotplug (need mode code for that though) ? - * - * If we don't hook up outputs now, then we only create - * /dev/fbX for the output that's enabled, that's good as - * the users console will be on that output. - * - * If we do hook up outputs that are disconnected now, then - * the user may end up having to muck about with the fbcon - * map flags to assign his console to the enabled output. Ugh. - */ - if (output->status != output_status_connected) - continue; - - if (list_empty(&output->modes)) - continue; - - des_mode = NULL; - found = 0; - list_for_each_entry(des_mode, &output->modes, head) { - if (des_mode->type & DRM_MODE_TYPE_PREFERRED) { - found = 1; - break; - } - } - - /* No preferred mode, let's just select the first available */ - if (!found) { - des_mode = NULL; - list_for_each_entry(des_mode, &output->modes, head) { - break; - } - } - - c = -1; - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - assigned = 0; - c++; - if ((output->possible_crtcs & (1 << c)) == 0) - continue; - - list_for_each_entry(output_equal, &dev->mode_config.output_list, head) { - if (output->id == output_equal->id) - continue; - - /* Find out if crtc has been assigned before */ - if (output_equal->crtc == crtc) - assigned = 1; - } - -#if 1 /* continue for now */ - if (assigned) - continue; -#endif - - o = -1; - list_for_each_entry(output_equal, &dev->mode_config.output_list, head) { - o++; - if (output->id == output_equal->id) - continue; - - list_for_each_entry(modes, &output->modes, head) { - list_for_each_entry(modes_equal, &output_equal->modes, head) { - if (drm_mode_equal (modes, modes_equal)) { - if ((output->possible_clones & output_equal->possible_clones) && (output_equal->crtc == crtc)) { - printk("Cloning %s (0x%lx) to %s (0x%lx)\n",drm_get_output_name(output),output->possible_clones,drm_get_output_name(output_equal),output_equal->possible_clones); - des_mode = modes; - assigned = 0; - goto clone; - } - } - } - } - } -clone: - /* crtc has been assigned skip it */ - if (assigned) - continue; - - /* Found a CRTC to attach to, do it ! */ - output->crtc = crtc; - output->crtc->desired_mode = des_mode; - output->initial_x = 0; - output->initial_y = 0; - DRM_DEBUG("Desired mode for CRTC %d is 0x%x:%s\n",c,des_mode->mode_id, des_mode->name); - break; - } - } -} -EXPORT_SYMBOL(drm_pick_crtcs); - -/** - * drm_initial_config - setup a sane initial output configuration - * @dev: DRM device - * @can_grow: this configuration is growable - * - * LOCKING: - * Called at init time, must take mode config lock. - * - * Scan the CRTCs and outputs and try to put together an initial setup. - * At the moment, this is a cloned configuration across all heads with - * a new framebuffer object as the backing store. - * - * RETURNS: - * Zero if everything went ok, nonzero otherwise. - */ -bool drm_initial_config(struct drm_device *dev, bool can_grow) -{ - struct drm_output *output; - struct drm_crtc *crtc; - int ret = false; - - mutex_lock(&dev->mode_config.mutex); - - drm_crtc_probe_output_modes(dev, 2048, 2048); - - drm_pick_crtcs(dev); - - /* This is a little screwy, as we've already walked the outputs - * above, but it's a little bit of magic too. There's the potential - * for things not to get setup above if an existing device gets - * re-assigned thus confusing the hardware. By walking the outputs - * this fixes up their crtc's. - */ - list_for_each_entry(output, &dev->mode_config.output_list, head) { - - /* can't setup the output if there's no assigned mode */ - if (!output->crtc || !output->crtc->desired_mode) - continue; - - dev->driver->fb_probe(dev, output->crtc, output); - - /* and needs an attached fb */ - if (output->crtc->fb) - drm_crtc_set_mode(output->crtc, output->crtc->desired_mode, 0, 0); - } - - drm_disable_unused_functions(dev); - - mutex_unlock(&dev->mode_config.mutex); - return ret; -} -EXPORT_SYMBOL(drm_initial_config); /** * drm_mode_config_cleanup - free up DRM mode_config info @@ -1105,179 +815,7 @@ void drm_mode_config_cleanup(struct drm_device *dev) } EXPORT_SYMBOL(drm_mode_config_cleanup); -/** - * drm_crtc_set_config - set a new config from userspace - * @crtc: CRTC to setup - * @crtc_info: user provided configuration - * @new_mode: new mode to set - * @output_set: set of outputs for the new config - * @fb: new framebuffer - * - * LOCKING: - * Caller must hold mode config lock. - * - * Setup a new configuration, provided by the user in @crtc_info, and enable - * it. - * - * RETURNS: - * Zero. (FIXME) - */ -int drm_crtc_set_config(struct drm_mode_set *set) -{ - struct drm_device *dev; - struct drm_crtc **save_crtcs, *new_crtc; - bool save_enabled; - bool changed = false; - bool flip_or_move = false; - struct drm_output *output; - int count = 0, ro; - - DRM_DEBUG("\n"); - - if (!set) - return -EINVAL; - - if (!set->crtc) - return -EINVAL; - - DRM_DEBUG("crtc: %p fb: %p outputs: %p num_outputs: %i (x, y) (%i, %i)\n", set->crtc, set->fb, set->outputs, set->num_outputs, set->x, set->y); - dev = set->crtc->dev; - - /* save previous config */ - save_enabled = set->crtc->enabled; - - /* this is meant to be num_output not num_crtc */ - save_crtcs = kzalloc(dev->mode_config.num_output * sizeof(struct drm_crtc *), GFP_KERNEL); - if (!save_crtcs) - return -ENOMEM; - - /* We should be able to check here if the fb has the same properties - * and then just flip_or_move it */ - if (set->crtc->fb != set->fb) - flip_or_move = true; - if (set->x != set->crtc->x || set->y != set->crtc->y) - flip_or_move = true; - - if (set->mode && !drm_mode_equal(set->mode, &set->crtc->mode)) { - DRM_DEBUG("modes are different\n"); - drm_mode_debug_printmodeline(&set->crtc->mode); - drm_mode_debug_printmodeline(set->mode); - changed = true; - } - - list_for_each_entry(output, &dev->mode_config.output_list, head) { - save_crtcs[count++] = output->crtc; - - if (output->crtc == set->crtc) - new_crtc = NULL; - else - new_crtc = output->crtc; - - for (ro = 0; ro < set->num_outputs; ro++) { - if (set->outputs[ro] == output) - new_crtc = set->crtc; - } - if (new_crtc != output->crtc) { - changed = true; - output->crtc = new_crtc; - } - } - - /* mode_set_base is not a required function */ - if (flip_or_move && !set->crtc->funcs->mode_set_base) - changed = true; - - if (changed) { - set->crtc->fb = set->fb; - set->crtc->enabled = (set->mode != NULL); - if (set->mode != NULL) { - DRM_DEBUG("attempting to set mode from userspace\n"); - drm_mode_debug_printmodeline(set->mode); - if (!drm_crtc_set_mode(set->crtc, set->mode, set->x, - set->y)) { - set->crtc->enabled = save_enabled; - count = 0; - list_for_each_entry(output, &dev->mode_config.output_list, head) - output->crtc = save_crtcs[count++]; - kfree(save_crtcs); - return -EINVAL; - } - /* TODO are these needed? */ - set->crtc->desired_x = set->x; - set->crtc->desired_y = set->y; - set->crtc->desired_mode = set->mode; - } - drm_disable_unused_functions(dev); - } else if (flip_or_move) { - if (set->crtc->fb != set->fb) - set->crtc->fb = set->fb; - set->crtc->funcs->mode_set_base(set->crtc, set->x, set->y); - } - - kfree(save_crtcs); - return 0; -} -EXPORT_SYMBOL(drm_crtc_set_config); - -/** - * drm_hotplug_stage_two - * @dev DRM device - * @output hotpluged output - * - * LOCKING. - * Caller must hold mode config lock, function might grab struct lock. - * - * Stage two of a hotplug. - * - * RETURNS: - * Zero on success, errno on failure. - */ -int drm_hotplug_stage_two(struct drm_device *dev, struct drm_output *output, - bool connected) -{ - int has_config = 0; - - dev->mode_config.hotplug_counter++; - - /* We might want to do something more here */ - if (!connected) { - DRM_DEBUG("not connected\n"); - return 0; - } - - if (output->crtc && output->crtc->desired_mode) { - DRM_DEBUG("drm thinks that the output already has a config\n"); - has_config = 1; - } - - drm_crtc_probe_output_modes(dev, 2048, 2048); - - if (!has_config) - drm_pick_crtcs(dev); - - if (!output->crtc || !output->crtc->desired_mode) { - DRM_DEBUG("could not find a desired mode or crtc for output\n"); - return 1; - } - - /* We should really check if there is a fb using this crtc */ - if (!has_config) - dev->driver->fb_probe(dev, output->crtc, output); - else { - dev->driver->fb_resize(dev, output->crtc); - - if (!drm_crtc_set_mode(output->crtc, output->crtc->desired_mode, 0, 0)) - DRM_ERROR("failed to set mode after hotplug\n"); - } - - drm_sysfs_hotplug_event(dev); - - drm_disable_unused_functions(dev); - - return 0; -} -EXPORT_SYMBOL(drm_hotplug_stage_two); int drm_mode_hotplug_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) @@ -1740,7 +1278,7 @@ int drm_mode_setcrtc(struct drm_device *dev, set.outputs = output_set; set.num_outputs = crtc_req->count_outputs; set.fb =fb; - ret = drm_crtc_set_config(&set); + ret = crtc->funcs->set_config(&set); out: kfree(output_set); @@ -2535,7 +2073,6 @@ int drm_mode_replacefb(struct drm_device *dev, { struct drm_mode_fb_cmd *r = data; struct drm_framebuffer *fb; - struct drm_crtc *crtc; struct drm_buffer_object *bo; int found = 0; struct drm_framebuffer *fbl = NULL; @@ -2574,12 +2111,18 @@ int drm_mode_replacefb(struct drm_device *dev, fb->depth = r->depth; fb->bo = bo; + if (dev->mode_config.funcs->resize_fb) + dev->mode_config.funcs->resize_fb(dev, fb); + else + ret = -EINVAL; +#if 0 /* find all crtcs connected to this fb */ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { if (crtc->fb->id == r->buffer_id) { crtc->funcs->mode_set_base(crtc, crtc->x, crtc->y); } } +#endif out: mutex_unlock(&dev->mode_config.mutex); return ret; diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index ae2dd173..957ecc2c 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -14,6 +14,7 @@ #include <linux/fb.h> struct drm_device; +struct drm_mode_set; /* * Note on terminology: here, for brevity and convenience, we refer to output @@ -313,20 +314,6 @@ struct drm_crtc_funcs { /* Restore CRTC state */ void (*restore)(struct drm_crtc *crtc); /* resume? */ - void (*prepare)(struct drm_crtc *crtc); - void (*commit)(struct drm_crtc *crtc); - - /* Provider can fixup or change mode timings before modeset occurs */ - bool (*mode_fixup)(struct drm_crtc *crtc, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode); - /* Actually set the mode */ - void (*mode_set)(struct drm_crtc *crtc, struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode, int x, int y); - - /* Move the crtc on the current fb to the given position *optional* */ - void (*mode_set_base)(struct drm_crtc *crtc, int x, int y); - /* cursor controls */ int (*cursor_set)(struct drm_crtc *crtc, struct drm_buffer_object *bo, uint32_t width, uint32_t height); @@ -337,6 +324,8 @@ struct drm_crtc_funcs { int regno); /* Driver cleanup routine */ void (*cleanup)(struct drm_crtc *crtc); + + int (*set_config)(struct drm_mode_set *set); }; /** @@ -371,6 +360,9 @@ struct drm_crtc { int desired_x, desired_y; const struct drm_crtc_funcs *funcs; void *driver_private; + + /* if you are using the helper */ + void *helper_private; }; extern struct drm_crtc *drm_crtc_create(struct drm_device *dev, @@ -399,21 +391,14 @@ struct drm_output_funcs { void (*dpms)(struct drm_output *output, int mode); void (*save)(struct drm_output *output); void (*restore)(struct drm_output *output); - int (*mode_valid)(struct drm_output *output, - struct drm_display_mode *mode); - bool (*mode_fixup)(struct drm_output *output, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode); - void (*prepare)(struct drm_output *output); - void (*commit)(struct drm_output *output); - void (*mode_set)(struct drm_output *output, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode); enum drm_output_status (*detect)(struct drm_output *output); int (*get_modes)(struct drm_output *output); bool (*set_property)(struct drm_output *output, struct drm_property *property, uint64_t val); void (*cleanup)(struct drm_output *output); + int (*mode_valid)(struct drm_output *output, + struct drm_display_mode *mode); + }; #define DRM_OUTPUT_MAX_UMODES 16 @@ -468,6 +453,8 @@ struct drm_output { struct drm_property_blob *edid_blob_ptr; u32 property_ids[DRM_OUTPUT_MAX_PROPERTY]; uint64_t property_values[DRM_OUTPUT_MAX_PROPERTY]; + + void *helper_private; }; /** @@ -501,7 +488,7 @@ struct drm_mode_set * the CRTC<->output mappings as needed and update its view of the screen. */ struct drm_mode_config_funcs { - bool (*resize)(struct drm_device *dev, int width, int height); + bool (*resize_fb)(struct drm_device *dev, struct drm_framebuffer *fb); }; /** @@ -597,18 +584,14 @@ extern int drm_output_property_get_value(struct drm_output *output, struct drm_property *property, uint64_t *value); extern struct drm_display_mode *drm_crtc_mode_create(struct drm_device *dev); -extern bool drm_initial_config(struct drm_device *dev, bool cangrow); extern void drm_framebuffer_set_object(struct drm_device *dev, unsigned long handle); extern struct drm_framebuffer *drm_framebuffer_create(struct drm_device *dev); extern void drm_framebuffer_destroy(struct drm_framebuffer *fb); extern int drmfb_probe(struct drm_device *dev, struct drm_crtc *crtc); extern int drmfb_remove(struct drm_device *dev, struct drm_framebuffer *fb); -extern int drm_crtc_set_config(struct drm_mode_set *set); -extern bool drm_crtc_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode, - int x, int y); +extern void drm_crtc_probe_output_modes(struct drm_device *dev, int maxX, int maxY); extern bool drm_crtc_in_use(struct drm_crtc *crtc); -extern int drm_hotplug_stage_two(struct drm_device *dev, struct drm_output *output, bool connected); extern int drm_output_attach_property(struct drm_output *output, struct drm_property *property, uint64_t init_val); 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 <airlied@linux.ie> + * + * 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 <eric@anholt.net> + * Dave Airlie <airlied@linux.ie> + * Jesse Barnes <jesse.barnes@intel.com> + */ + +#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); diff --git a/linux-core/drm_crtc_helper.h b/linux-core/drm_crtc_helper.h new file mode 100644 index 00000000..f56b97c6 --- /dev/null +++ b/linux-core/drm_crtc_helper.h @@ -0,0 +1,69 @@ +/* + * Copyright © 2006 Keith Packard + * Copyright © 2007 Intel Corporation + * Jesse Barnes <jesse.barnes@intel.com> + */ + +/* + * The DRM mode setting helper functions are common code for drivers to use if they wish. + * Drivers are not forced to use this code in their implementations but it would be useful + * if they code they do use at least provides a consistent interface and operation to userspace + */ + +#ifndef __DRM_CRTC_HELPER_H__ +#define __DRM_CRTC_HELPER_H__ + +#include <linux/i2c.h> +#include <linux/spinlock.h> +#include <linux/types.h> +#include <linux/idr.h> + +#include <linux/fb.h> + +struct drm_crtc_helper_funcs { + void (*prepare)(struct drm_crtc *crtc); + void (*commit)(struct drm_crtc *crtc); + + /* Provider can fixup or change mode timings before modeset occurs */ + bool (*mode_fixup)(struct drm_crtc *crtc, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode); + /* Actually set the mode */ + void (*mode_set)(struct drm_crtc *crtc, struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode, int x, int y); + + /* Move the crtc on the current fb to the given position *optional* */ + void (*mode_set_base)(struct drm_crtc *crtc, int x, int y); +}; + +struct drm_output_helper_funcs { + bool (*mode_fixup)(struct drm_output *output, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode); + void (*prepare)(struct drm_output *output); + void (*commit)(struct drm_output *output); + void (*mode_set)(struct drm_output *output, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode); +}; + +extern int drm_helper_hotplug_stage_two(struct drm_device *dev, struct drm_output *output, + bool connected); +extern bool drm_helper_initial_config(struct drm_device *dev, bool can_grow); +extern int drm_crtc_helper_set_config(struct drm_mode_set *set); +extern bool drm_crtc_helper_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode, + int x, int y); + +static inline void drm_crtc_helper_add(struct drm_crtc *crtc, const struct drm_crtc_helper_funcs *funcs) +{ + crtc->helper_private = (void *)funcs; +} + +static inline void drm_output_helper_add(struct drm_output *output, const struct drm_output_helper_funcs *funcs) +{ + output->helper_private = (void *)funcs; +} + + + +#endif diff --git a/linux-core/intel_crt.c b/linux-core/intel_crt.c index ef40871e..3c5dae1a 100644 --- a/linux-core/intel_crt.c +++ b/linux-core/intel_crt.c @@ -28,6 +28,7 @@ #include "drmP.h" #include "drm.h" #include "drm_crtc.h" +#include "drm_crtc_helper.h" #include "intel_drv.h" #include "i915_drm.h" #include "i915_drv.h" @@ -220,19 +221,24 @@ static bool intel_crt_set_property(struct drm_output *output, /* * Routines for controlling stuff on the analog port */ + +static const struct drm_output_helper_funcs intel_crt_helper_funcs = { + .mode_fixup = intel_crt_mode_fixup, + .prepare = intel_output_prepare, + .commit = intel_output_commit, + .mode_set = intel_crt_mode_set, +}; + static const struct drm_output_funcs intel_crt_output_funcs = { .dpms = intel_crt_dpms, .save = intel_crt_save, .restore = intel_crt_restore, - .mode_valid = intel_crt_mode_valid, - .mode_fixup = intel_crt_mode_fixup, - .prepare = intel_output_prepare, - .mode_set = intel_crt_mode_set, - .commit = intel_output_commit, .detect = intel_crt_detect, .get_modes = intel_crt_get_modes, .cleanup = intel_crt_destroy, .set_property = intel_crt_set_property, + .mode_valid = intel_crt_mode_valid, + }; void intel_crt_init(struct drm_device *dev) @@ -261,6 +267,7 @@ void intel_crt_init(struct drm_device *dev) output->interlace_allowed = 0; output->doublescan_allowed = 0; + drm_output_helper_add(output, &intel_crt_helper_funcs); drm_sysfs_output_add(output); drm_output_attach_property(output, dev->mode_config.connector_type_property, ConnectorVGA); diff --git a/linux-core/intel_display.c b/linux-core/intel_display.c index e7162c2c..a2307a3d 100644 --- a/linux-core/intel_display.c +++ b/linux-core/intel_display.c @@ -30,6 +30,8 @@ #include "i915_drm.h" #include "i915_drv.h" +#include "drm_crtc_helper.h" + bool intel_pipe_has_type (struct drm_crtc *crtc, int type); typedef struct { @@ -1090,6 +1092,7 @@ struct drm_crtc *intel_get_load_detect_pipe(struct drm_output *output, struct drm_crtc *possible_crtc; struct drm_crtc *supported_crtc =NULL; struct drm_crtc *crtc = NULL; + struct drm_output_helper_funcs *output_funcs; int i = -1; /* @@ -1147,14 +1150,15 @@ struct drm_crtc *intel_get_load_detect_pipe(struct drm_output *output, if (!crtc->enabled) { if (!mode) mode = &load_detect_mode; - drm_crtc_set_mode(crtc, mode, 0, 0); + drm_crtc_helper_set_mode(crtc, mode, 0, 0); } else { if (intel_crtc->dpms_mode != DPMSModeOn) crtc->funcs->dpms(crtc, DPMSModeOn); + output_funcs = output->helper_private; /* Add this output to the crtc */ - output->funcs->mode_set(output, &crtc->mode, &crtc->mode); - output->funcs->commit(output); + output_funcs->mode_set(output, &crtc->mode, &crtc->mode); + output_funcs->commit(output); } /* let the output get through one full cycle before testing */ intel_wait_for_vblank(dev); @@ -1293,16 +1297,20 @@ struct drm_display_mode *intel_crtc_mode_get(struct drm_device *dev, return mode; } -static const struct drm_crtc_funcs intel_crtc_funcs = { - .dpms = intel_crtc_dpms, +static const struct drm_crtc_helper_funcs intel_helper_funcs = { .mode_fixup = intel_crtc_mode_fixup, .mode_set = intel_crtc_mode_set, .mode_set_base = intel_pipe_set_base, + .prepare = intel_crtc_prepare, + .commit = intel_crtc_commit, +}; + +static const struct drm_crtc_funcs intel_crtc_funcs = { + .dpms = intel_crtc_dpms, .cursor_set = intel_crtc_cursor_set, .cursor_move = intel_crtc_cursor_move, .gamma_set = intel_crtc_gamma_set, - .prepare = intel_crtc_prepare, - .commit = intel_crtc_commit, + .set_config = drm_crtc_helper_set_config, }; @@ -1331,6 +1339,7 @@ void intel_crtc_init(struct drm_device *dev, int pipe) intel_crtc->cursor_addr = 0; intel_crtc->dpms_mode = DPMSModeOff; + drm_crtc_helper_add(crtc, &intel_helper_funcs); crtc->driver_private = intel_crtc; } @@ -1418,6 +1427,10 @@ static void intel_setup_outputs(struct drm_device *dev) } } +static const struct drm_mode_config_funcs intel_mode_funcs = { + .resize_fb = NULL, +}; + void intel_modeset_init(struct drm_device *dev) { int num_pipe; @@ -1428,6 +1441,8 @@ void intel_modeset_init(struct drm_device *dev) dev->mode_config.min_width = 0; dev->mode_config.min_height = 0; + dev->mode_config.funcs = (void *)&intel_mode_funcs; + if (IS_I965G(dev)) { dev->mode_config.max_width = 8192; dev->mode_config.max_height = 8192; diff --git a/linux-core/intel_drv.h b/linux-core/intel_drv.h index e97117de..9f8ca8dd 100644 --- a/linux-core/intel_drv.h +++ b/linux-core/intel_drv.h @@ -11,6 +11,7 @@ #include <linux/i2c-algo-bit.h> #include "drm_crtc.h" +#include "drm_crtc_helper.h" /* * Display related stuff */ diff --git a/linux-core/intel_dvo.c b/linux-core/intel_dvo.c index 6f319107..5a7da276 100644 --- a/linux-core/intel_dvo.c +++ b/linux-core/intel_dvo.c @@ -325,19 +325,21 @@ static struct drm_crtc *intel_dvo_get_crtc(struct drm_output *output) } #endif +static const struct drm_output_helper_funcs intel_dvo_helper_funcs = { + .mode_fixup = intel_dvo_mode_fixup, + .prepare = intel_output_prepare, + .mode_set = intel_dvo_mode_set, + .commit = intel_output_commit, +}; static const struct drm_output_funcs intel_dvo_output_funcs = { .dpms = intel_dvo_dpms, .save = intel_dvo_save, .restore = intel_dvo_restore, - .mode_valid = intel_dvo_mode_valid, - .mode_fixup = intel_dvo_mode_fixup, - .prepare = intel_output_prepare, - .mode_set = intel_dvo_mode_set, - .commit = intel_output_commit, .detect = intel_dvo_detect, .get_modes = intel_dvo_get_modes, - .cleanup = intel_dvo_destroy + .cleanup = intel_dvo_destroy, + .mode_valid = intel_dvo_mode_valid, }; /** @@ -457,6 +459,7 @@ void intel_dvo_init(struct drm_device *dev) goto free_i2c; } + drm_output_helper_add(output, &intel_dvo_helper_funcs); output->driver_private = intel_output; output->display_info.subpixel_order = SubPixelHorizontalRGB; output->interlace_allowed = false; diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index 4f5a0000..05fc3b29 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -341,7 +341,7 @@ static int intelfb_set_par(struct fb_info *info) return 0; #else - return drm_crtc_set_config(&par->set); + return par->set.crtc->funcs->set_config(&par->set); #endif } @@ -496,11 +496,11 @@ static int intelfb_pan_display(struct fb_var_screeninfo *var, struct intelfb_par *par = info->par; int ret; DRM_DEBUG("\n"); - + par->set.x = var->xoffset; par->set.y = var->yoffset; - ret = drm_crtc_set_config(&par->set); + ret = par->set.crtc->funcs->set_config(&par->set); if (!ret) { info->var.xoffset = var->xoffset; diff --git a/linux-core/intel_lvds.c b/linux-core/intel_lvds.c index 6b6d3162..f71dd436 100644 --- a/linux-core/intel_lvds.c +++ b/linux-core/intel_lvds.c @@ -332,18 +332,21 @@ static void intel_lvds_destroy(struct drm_output *output) kfree(output->driver_private); } -static const struct drm_output_funcs intel_lvds_output_funcs = { - .dpms = intel_lvds_dpms, - .save = intel_lvds_save, - .restore = intel_lvds_restore, - .mode_valid = intel_lvds_mode_valid, +static const struct drm_output_helper_funcs intel_lvds_helper_funcs = { .mode_fixup = intel_lvds_mode_fixup, .prepare = intel_lvds_prepare, .mode_set = intel_lvds_mode_set, .commit = intel_lvds_commit, +}; + +static const struct drm_output_funcs intel_lvds_output_funcs = { + .dpms = intel_lvds_dpms, + .save = intel_lvds_save, + .restore = intel_lvds_restore, .detect = intel_lvds_detect, .get_modes = intel_lvds_get_modes, - .cleanup = intel_lvds_destroy + .cleanup = intel_lvds_destroy, + .mode_valid = intel_lvds_mode_valid, }; /** @@ -375,6 +378,7 @@ void intel_lvds_init(struct drm_device *dev) } intel_output->type = INTEL_OUTPUT_LVDS; + drm_output_helper_add(output, &intel_lvds_helper_funcs); output->driver_private = intel_output; output->display_info.subpixel_order = SubPixelHorizontalRGB; output->interlace_allowed = FALSE; diff --git a/linux-core/intel_sdvo.c b/linux-core/intel_sdvo.c index ba6fe9a8..41da034d 100644 --- a/linux-core/intel_sdvo.c +++ b/linux-core/intel_sdvo.c @@ -972,18 +972,21 @@ static void intel_sdvo_destroy(struct drm_output *output) } } -static const struct drm_output_funcs intel_sdvo_output_funcs = { - .dpms = intel_sdvo_dpms, - .save = intel_sdvo_save, - .restore = intel_sdvo_restore, - .mode_valid = intel_sdvo_mode_valid, +static const struct drm_output_helper_funcs intel_sdvo_helper_funcs = { .mode_fixup = intel_sdvo_mode_fixup, .prepare = intel_output_prepare, .mode_set = intel_sdvo_mode_set, .commit = intel_output_commit, +}; + +static const struct drm_output_funcs intel_sdvo_output_funcs = { + .dpms = intel_sdvo_dpms, + .save = intel_sdvo_save, + .restore = intel_sdvo_restore, .detect = intel_sdvo_detect, .get_modes = intel_sdvo_get_modes, - .cleanup = intel_sdvo_destroy + .cleanup = intel_sdvo_destroy, + .mode_valid = intel_sdvo_mode_valid, }; void intel_sdvo_init(struct drm_device *dev, int output_device) @@ -1010,6 +1013,7 @@ void intel_sdvo_init(struct drm_device *dev, int output_device) sdvo_priv = (struct intel_sdvo_priv *)(intel_output + 1); intel_output->type = INTEL_OUTPUT_SDVO; + drm_output_helper_add(output, &intel_sdvo_helper_funcs); output->driver_private = intel_output; output->interlace_allowed = 0; output->doublescan_allowed = 0; diff --git a/linux-core/intel_tv.c b/linux-core/intel_tv.c index 650c46f7..18fb1f37 100644 --- a/linux-core/intel_tv.c +++ b/linux-core/intel_tv.c @@ -1590,15 +1590,18 @@ out: return ret; } +static const struct drm_output_helper_funcs intel_tv_helper_funcs = { + .mode_fixup = intel_tv_mode_fixup, + .prepare = intel_output_prepare, + .mode_set = intel_tv_mode_set, + .commit = intel_output_commit, +}; + static const struct drm_output_funcs intel_tv_output_funcs = { .dpms = intel_tv_dpms, .save = intel_tv_save, .restore = intel_tv_restore, .mode_valid = intel_tv_mode_valid, - .mode_fixup = intel_tv_mode_fixup, - .prepare = intel_output_prepare, - .mode_set = intel_tv_mode_set, - .commit = intel_output_commit, .detect = intel_tv_detect, .get_modes = intel_tv_get_modes, .cleanup = intel_tv_destroy, @@ -1674,6 +1677,7 @@ intel_tv_init(struct drm_device *dev) tv_priv->tv_format = kstrdup(tv_modes[initial_mode].name, GFP_KERNEL); + drm_output_helper_add(output, &intel_tv_helper_funcs); output->driver_private = intel_output; output->interlace_allowed = FALSE; output->doublescan_allowed = FALSE; diff --git a/shared-core/i915_init.c b/shared-core/i915_init.c index bda15e01..f03f8949 100644 --- a/shared-core/i915_init.c +++ b/shared-core/i915_init.c @@ -13,6 +13,7 @@ #include "i915_drm.h" #include "i915_drv.h" #include "intel_bios.h" +#include "intel_drv.h" /** * i915_probe_agp - get AGP bootup configuration @@ -232,7 +233,7 @@ int i915_load_modeset_init(struct drm_device *dev) } intel_modeset_init(dev); - drm_initial_config(dev, false); + drm_helper_initial_config(dev, false); drm_mm_print(&dev->bm.man[DRM_BO_MEM_VRAM].manager, "VRAM"); drm_mm_print(&dev->bm.man[DRM_BO_MEM_TT].manager, "TT"); diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index 592e881b..ccedc70e 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -31,6 +31,7 @@ #include "i915_drm.h" #include "i915_drv.h" #include "intel_drv.h" +#include "drm_crtc_helper.h" #define MAX_NOPID ((u32)~0) @@ -471,8 +472,8 @@ static void i915_hotplug_tv(struct drm_device *dev) goto unlock; status = output->funcs->detect(output); - drm_hotplug_stage_two(dev, output, - status == output_status_connected ? 1 : 0); + drm_helper_hotplug_stage_two(dev, output, + status == output_status_connected ? 1 : 0); unlock: mutex_unlock(&dev->mode_config.mutex); @@ -497,7 +498,7 @@ static void i915_hotplug_crt(struct drm_device *dev, bool isconnected) if (iout == 0) goto unlock; - drm_hotplug_stage_two(dev, output, isconnected); + drm_helper_hotplug_stage_two(dev, output, isconnected); unlock: mutex_unlock(&dev->mode_config.mutex); @@ -518,9 +519,9 @@ static void i915_hotplug_sdvo(struct drm_device *dev, int sdvoB) status = output->funcs->detect(output); if (status != output_status_connected) - drm_hotplug_stage_two(dev, output, false); + drm_helper_hotplug_stage_two(dev, output, false); else - drm_hotplug_stage_two(dev, output, true); + drm_helper_hotplug_stage_two(dev, output, true); intel_sdvo_set_hotplug(output, 1); |