summaryrefslogtreecommitdiff
path: root/linux-core
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2008-05-29 14:02:14 +1000
committerDave Airlie <airlied@redhat.com>2008-05-29 14:02:14 +1000
commitdf8cd54286fbae5903d8ede390ec4a11cb6c4b6c (patch)
tree915a1b55354bbd6e2f32f68ecd4d1fde8fb5cae6 /linux-core
parentee5afc63428488c9c39e5ecd7d8cdc646a7b65b7 (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.
Diffstat (limited to 'linux-core')
-rw-r--r--linux-core/Makefile.kernel2
-rw-r--r--linux-core/drm_crtc.c471
-rw-r--r--linux-core/drm_crtc.h43
-rw-r--r--linux-core/drm_crtc_helper.c515
-rw-r--r--linux-core/drm_crtc_helper.h69
-rw-r--r--linux-core/intel_crt.c17
-rw-r--r--linux-core/intel_display.c29
-rw-r--r--linux-core/intel_drv.h1
-rw-r--r--linux-core/intel_dvo.c15
-rw-r--r--linux-core/intel_fb.c6
-rw-r--r--linux-core/intel_lvds.c16
-rw-r--r--linux-core/intel_sdvo.c16
-rw-r--r--linux-core/intel_tv.c12
13 files changed, 680 insertions, 532 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;