modesetting: reorganise code into core and helper functions.
authorDave Airlie <airlied@redhat.com>
Thu, 29 May 2008 04:02:14 +0000 (14:02 +1000)
committerDave Airlie <airlied@redhat.com>
Thu, 29 May 2008 04:02:14 +0000 (14:02 +1000)
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.

15 files changed:
linux-core/Makefile.kernel
linux-core/drm_crtc.c
linux-core/drm_crtc.h
linux-core/drm_crtc_helper.c [new file with mode: 0644]
linux-core/drm_crtc_helper.h [new file with mode: 0644]
linux-core/intel_crt.c
linux-core/intel_display.c
linux-core/intel_drv.h
linux-core/intel_dvo.c
linux-core/intel_fb.c
linux-core/intel_lvds.c
linux-core/intel_sdvo.c
linux-core/intel_tv.c
shared-core/i915_init.c
shared-core/i915_irq.c

index f77f864..ac9baf0 100644 (file)
@@ -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
index e05466e..a4a5108 100644 (file)
@@ -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;
index ae2dd17..957ecc2 100644 (file)
@@ -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 (file)
index 0000000..f776dbe
--- /dev/null
@@ -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 (file)
index 0000000..f56b97c
--- /dev/null
@@ -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
index ef40871..3c5dae1 100644 (file)
@@ -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);
index e7162c2..a2307a3 100644 (file)
@@ -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;
index e97117d..9f8ca8d 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/i2c-algo-bit.h>
 #include "drm_crtc.h"
 
+#include "drm_crtc_helper.h"
 /*
  * Display related stuff
  */
index 6f31910..5a7da27 100644 (file)
@@ -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;
index 4f5a000..05fc3b2 100644 (file)
@@ -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;
index 6b6d316..f71dd43 100644 (file)
@@ -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;
index ba6fe9a..41da034 100644 (file)
@@ -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;
index 650c46f..18fb1f3 100644 (file)
@@ -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;
index bda15e0..f03f894 100644 (file)
@@ -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");
index 592e881..ccedc70 100644 (file)
@@ -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);