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.
main
Dave Airlie 2008-05-29 14:02:14 +10:00
parent ee5afc6342
commit df8cd54286
15 changed files with 688 additions and 538 deletions

View 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_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_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_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 tdfx-objs := tdfx_drv.o
r128-objs := r128_drv.o r128_cce.o r128_state.o r128_irq.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 mga-objs := mga_drv.o mga_dma.o mga_state.o mga_warp.o mga_irq.o

View 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); 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 * drm_disable_unused_functions - disable unused objects
@ -896,171 +769,8 @@ out_err:
return ret; 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 * 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); 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, int drm_mode_hotplug_ioctl(struct drm_device *dev,
void *data, struct drm_file *file_priv) void *data, struct drm_file *file_priv)
@ -1740,7 +1278,7 @@ int drm_mode_setcrtc(struct drm_device *dev,
set.outputs = output_set; set.outputs = output_set;
set.num_outputs = crtc_req->count_outputs; set.num_outputs = crtc_req->count_outputs;
set.fb =fb; set.fb =fb;
ret = drm_crtc_set_config(&set); ret = crtc->funcs->set_config(&set);
out: out:
kfree(output_set); kfree(output_set);
@ -2535,7 +2073,6 @@ int drm_mode_replacefb(struct drm_device *dev,
{ {
struct drm_mode_fb_cmd *r = data; struct drm_mode_fb_cmd *r = data;
struct drm_framebuffer *fb; struct drm_framebuffer *fb;
struct drm_crtc *crtc;
struct drm_buffer_object *bo; struct drm_buffer_object *bo;
int found = 0; int found = 0;
struct drm_framebuffer *fbl = NULL; struct drm_framebuffer *fbl = NULL;
@ -2574,12 +2111,18 @@ int drm_mode_replacefb(struct drm_device *dev,
fb->depth = r->depth; fb->depth = r->depth;
fb->bo = bo; 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 */ /* find all crtcs connected to this fb */
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
if (crtc->fb->id == r->buffer_id) { if (crtc->fb->id == r->buffer_id) {
crtc->funcs->mode_set_base(crtc, crtc->x, crtc->y); crtc->funcs->mode_set_base(crtc, crtc->x, crtc->y);
} }
} }
#endif
out: out:
mutex_unlock(&dev->mode_config.mutex); mutex_unlock(&dev->mode_config.mutex);
return ret; return ret;

View File

@ -14,6 +14,7 @@
#include <linux/fb.h> #include <linux/fb.h>
struct drm_device; struct drm_device;
struct drm_mode_set;
/* /*
* Note on terminology: here, for brevity and convenience, we refer to output * Note on terminology: here, for brevity and convenience, we refer to output
@ -313,20 +314,6 @@ struct drm_crtc_funcs {
/* Restore CRTC state */ /* Restore CRTC state */
void (*restore)(struct drm_crtc *crtc); /* resume? */ 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 */ /* cursor controls */
int (*cursor_set)(struct drm_crtc *crtc, struct drm_buffer_object *bo, int (*cursor_set)(struct drm_crtc *crtc, struct drm_buffer_object *bo,
uint32_t width, uint32_t height); uint32_t width, uint32_t height);
@ -337,6 +324,8 @@ struct drm_crtc_funcs {
int regno); int regno);
/* Driver cleanup routine */ /* Driver cleanup routine */
void (*cleanup)(struct drm_crtc *crtc); 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; int desired_x, desired_y;
const struct drm_crtc_funcs *funcs; const struct drm_crtc_funcs *funcs;
void *driver_private; void *driver_private;
/* if you are using the helper */
void *helper_private;
}; };
extern struct drm_crtc *drm_crtc_create(struct drm_device *dev, 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 (*dpms)(struct drm_output *output, int mode);
void (*save)(struct drm_output *output); void (*save)(struct drm_output *output);
void (*restore)(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); enum drm_output_status (*detect)(struct drm_output *output);
int (*get_modes)(struct drm_output *output); int (*get_modes)(struct drm_output *output);
bool (*set_property)(struct drm_output *output, struct drm_property *property, bool (*set_property)(struct drm_output *output, struct drm_property *property,
uint64_t val); uint64_t val);
void (*cleanup)(struct drm_output *output); void (*cleanup)(struct drm_output *output);
int (*mode_valid)(struct drm_output *output,
struct drm_display_mode *mode);
}; };
#define DRM_OUTPUT_MAX_UMODES 16 #define DRM_OUTPUT_MAX_UMODES 16
@ -468,6 +453,8 @@ struct drm_output {
struct drm_property_blob *edid_blob_ptr; struct drm_property_blob *edid_blob_ptr;
u32 property_ids[DRM_OUTPUT_MAX_PROPERTY]; u32 property_ids[DRM_OUTPUT_MAX_PROPERTY];
uint64_t property_values[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. * the CRTC<->output mappings as needed and update its view of the screen.
*/ */
struct drm_mode_config_funcs { 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, struct drm_property *property,
uint64_t *value); uint64_t *value);
extern struct drm_display_mode *drm_crtc_mode_create(struct drm_device *dev); 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, extern void drm_framebuffer_set_object(struct drm_device *dev,
unsigned long handle); unsigned long handle);
extern struct drm_framebuffer *drm_framebuffer_create(struct drm_device *dev); extern struct drm_framebuffer *drm_framebuffer_create(struct drm_device *dev);
extern void drm_framebuffer_destroy(struct drm_framebuffer *fb); extern void drm_framebuffer_destroy(struct drm_framebuffer *fb);
extern int drmfb_probe(struct drm_device *dev, struct drm_crtc *crtc); 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 drmfb_remove(struct drm_device *dev, struct drm_framebuffer *fb);
extern int drm_crtc_set_config(struct drm_mode_set *set); extern void drm_crtc_probe_output_modes(struct drm_device *dev, int maxX, int maxY);
extern bool drm_crtc_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode,
int x, int y);
extern bool drm_crtc_in_use(struct drm_crtc *crtc); 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, extern int drm_output_attach_property(struct drm_output *output,
struct drm_property *property, uint64_t init_val); struct drm_property *property, uint64_t init_val);

View File

@ -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);

View File

@ -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

View File

@ -28,6 +28,7 @@
#include "drmP.h" #include "drmP.h"
#include "drm.h" #include "drm.h"
#include "drm_crtc.h" #include "drm_crtc.h"
#include "drm_crtc_helper.h"
#include "intel_drv.h" #include "intel_drv.h"
#include "i915_drm.h" #include "i915_drm.h"
#include "i915_drv.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 * 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 = { static const struct drm_output_funcs intel_crt_output_funcs = {
.dpms = intel_crt_dpms, .dpms = intel_crt_dpms,
.save = intel_crt_save, .save = intel_crt_save,
.restore = intel_crt_restore, .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, .detect = intel_crt_detect,
.get_modes = intel_crt_get_modes, .get_modes = intel_crt_get_modes,
.cleanup = intel_crt_destroy, .cleanup = intel_crt_destroy,
.set_property = intel_crt_set_property, .set_property = intel_crt_set_property,
.mode_valid = intel_crt_mode_valid,
}; };
void intel_crt_init(struct drm_device *dev) 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->interlace_allowed = 0;
output->doublescan_allowed = 0; output->doublescan_allowed = 0;
drm_output_helper_add(output, &intel_crt_helper_funcs);
drm_sysfs_output_add(output); drm_sysfs_output_add(output);
drm_output_attach_property(output, dev->mode_config.connector_type_property, ConnectorVGA); drm_output_attach_property(output, dev->mode_config.connector_type_property, ConnectorVGA);

View File

@ -30,6 +30,8 @@
#include "i915_drm.h" #include "i915_drm.h"
#include "i915_drv.h" #include "i915_drv.h"
#include "drm_crtc_helper.h"
bool intel_pipe_has_type (struct drm_crtc *crtc, int type); bool intel_pipe_has_type (struct drm_crtc *crtc, int type);
typedef struct { 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 *possible_crtc;
struct drm_crtc *supported_crtc =NULL; struct drm_crtc *supported_crtc =NULL;
struct drm_crtc *crtc = NULL; struct drm_crtc *crtc = NULL;
struct drm_output_helper_funcs *output_funcs;
int i = -1; int i = -1;
/* /*
@ -1147,14 +1150,15 @@ struct drm_crtc *intel_get_load_detect_pipe(struct drm_output *output,
if (!crtc->enabled) { if (!crtc->enabled) {
if (!mode) if (!mode)
mode = &load_detect_mode; mode = &load_detect_mode;
drm_crtc_set_mode(crtc, mode, 0, 0); drm_crtc_helper_set_mode(crtc, mode, 0, 0);
} else { } else {
if (intel_crtc->dpms_mode != DPMSModeOn) if (intel_crtc->dpms_mode != DPMSModeOn)
crtc->funcs->dpms(crtc, DPMSModeOn); crtc->funcs->dpms(crtc, DPMSModeOn);
output_funcs = output->helper_private;
/* Add this output to the crtc */ /* Add this output to the crtc */
output->funcs->mode_set(output, &crtc->mode, &crtc->mode); output_funcs->mode_set(output, &crtc->mode, &crtc->mode);
output->funcs->commit(output); output_funcs->commit(output);
} }
/* let the output get through one full cycle before testing */ /* let the output get through one full cycle before testing */
intel_wait_for_vblank(dev); intel_wait_for_vblank(dev);
@ -1293,16 +1297,20 @@ struct drm_display_mode *intel_crtc_mode_get(struct drm_device *dev,
return mode; return mode;
} }
static const struct drm_crtc_funcs intel_crtc_funcs = { static const struct drm_crtc_helper_funcs intel_helper_funcs = {
.dpms = intel_crtc_dpms,
.mode_fixup = intel_crtc_mode_fixup, .mode_fixup = intel_crtc_mode_fixup,
.mode_set = intel_crtc_mode_set, .mode_set = intel_crtc_mode_set,
.mode_set_base = intel_pipe_set_base, .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_set = intel_crtc_cursor_set,
.cursor_move = intel_crtc_cursor_move, .cursor_move = intel_crtc_cursor_move,
.gamma_set = intel_crtc_gamma_set, .gamma_set = intel_crtc_gamma_set,
.prepare = intel_crtc_prepare, .set_config = drm_crtc_helper_set_config,
.commit = intel_crtc_commit,
}; };
@ -1331,6 +1339,7 @@ void intel_crtc_init(struct drm_device *dev, int pipe)
intel_crtc->cursor_addr = 0; intel_crtc->cursor_addr = 0;
intel_crtc->dpms_mode = DPMSModeOff; intel_crtc->dpms_mode = DPMSModeOff;
drm_crtc_helper_add(crtc, &intel_helper_funcs);
crtc->driver_private = intel_crtc; 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) void intel_modeset_init(struct drm_device *dev)
{ {
int num_pipe; 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_width = 0;
dev->mode_config.min_height = 0; dev->mode_config.min_height = 0;
dev->mode_config.funcs = (void *)&intel_mode_funcs;
if (IS_I965G(dev)) { if (IS_I965G(dev)) {
dev->mode_config.max_width = 8192; dev->mode_config.max_width = 8192;
dev->mode_config.max_height = 8192; dev->mode_config.max_height = 8192;

View File

@ -11,6 +11,7 @@
#include <linux/i2c-algo-bit.h> #include <linux/i2c-algo-bit.h>
#include "drm_crtc.h" #include "drm_crtc.h"
#include "drm_crtc_helper.h"
/* /*
* Display related stuff * Display related stuff
*/ */

View File

@ -325,19 +325,21 @@ static struct drm_crtc *intel_dvo_get_crtc(struct drm_output *output)
} }
#endif #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 = { static const struct drm_output_funcs intel_dvo_output_funcs = {
.dpms = intel_dvo_dpms, .dpms = intel_dvo_dpms,
.save = intel_dvo_save, .save = intel_dvo_save,
.restore = intel_dvo_restore, .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, .detect = intel_dvo_detect,
.get_modes = intel_dvo_get_modes, .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; goto free_i2c;
} }
drm_output_helper_add(output, &intel_dvo_helper_funcs);
output->driver_private = intel_output; output->driver_private = intel_output;
output->display_info.subpixel_order = SubPixelHorizontalRGB; output->display_info.subpixel_order = SubPixelHorizontalRGB;
output->interlace_allowed = false; output->interlace_allowed = false;

View File

@ -341,7 +341,7 @@ static int intelfb_set_par(struct fb_info *info)
return 0; return 0;
#else #else
return drm_crtc_set_config(&par->set); return par->set.crtc->funcs->set_config(&par->set);
#endif #endif
} }
@ -500,7 +500,7 @@ static int intelfb_pan_display(struct fb_var_screeninfo *var,
par->set.x = var->xoffset; par->set.x = var->xoffset;
par->set.y = var->yoffset; par->set.y = var->yoffset;
ret = drm_crtc_set_config(&par->set); ret = par->set.crtc->funcs->set_config(&par->set);
if (!ret) { if (!ret) {
info->var.xoffset = var->xoffset; info->var.xoffset = var->xoffset;

View File

@ -332,18 +332,21 @@ static void intel_lvds_destroy(struct drm_output *output)
kfree(output->driver_private); kfree(output->driver_private);
} }
static const struct drm_output_funcs intel_lvds_output_funcs = { static const struct drm_output_helper_funcs intel_lvds_helper_funcs = {
.dpms = intel_lvds_dpms,
.save = intel_lvds_save,
.restore = intel_lvds_restore,
.mode_valid = intel_lvds_mode_valid,
.mode_fixup = intel_lvds_mode_fixup, .mode_fixup = intel_lvds_mode_fixup,
.prepare = intel_lvds_prepare, .prepare = intel_lvds_prepare,
.mode_set = intel_lvds_mode_set, .mode_set = intel_lvds_mode_set,
.commit = intel_lvds_commit, .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, .detect = intel_lvds_detect,
.get_modes = intel_lvds_get_modes, .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; intel_output->type = INTEL_OUTPUT_LVDS;
drm_output_helper_add(output, &intel_lvds_helper_funcs);
output->driver_private = intel_output; output->driver_private = intel_output;
output->display_info.subpixel_order = SubPixelHorizontalRGB; output->display_info.subpixel_order = SubPixelHorizontalRGB;
output->interlace_allowed = FALSE; output->interlace_allowed = FALSE;

View File

@ -972,18 +972,21 @@ static void intel_sdvo_destroy(struct drm_output *output)
} }
} }
static const struct drm_output_funcs intel_sdvo_output_funcs = { static const struct drm_output_helper_funcs intel_sdvo_helper_funcs = {
.dpms = intel_sdvo_dpms,
.save = intel_sdvo_save,
.restore = intel_sdvo_restore,
.mode_valid = intel_sdvo_mode_valid,
.mode_fixup = intel_sdvo_mode_fixup, .mode_fixup = intel_sdvo_mode_fixup,
.prepare = intel_output_prepare, .prepare = intel_output_prepare,
.mode_set = intel_sdvo_mode_set, .mode_set = intel_sdvo_mode_set,
.commit = intel_output_commit, .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, .detect = intel_sdvo_detect,
.get_modes = intel_sdvo_get_modes, .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) 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); sdvo_priv = (struct intel_sdvo_priv *)(intel_output + 1);
intel_output->type = INTEL_OUTPUT_SDVO; intel_output->type = INTEL_OUTPUT_SDVO;
drm_output_helper_add(output, &intel_sdvo_helper_funcs);
output->driver_private = intel_output; output->driver_private = intel_output;
output->interlace_allowed = 0; output->interlace_allowed = 0;
output->doublescan_allowed = 0; output->doublescan_allowed = 0;

View File

@ -1590,15 +1590,18 @@ out:
return ret; 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 = { static const struct drm_output_funcs intel_tv_output_funcs = {
.dpms = intel_tv_dpms, .dpms = intel_tv_dpms,
.save = intel_tv_save, .save = intel_tv_save,
.restore = intel_tv_restore, .restore = intel_tv_restore,
.mode_valid = intel_tv_mode_valid, .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, .detect = intel_tv_detect,
.get_modes = intel_tv_get_modes, .get_modes = intel_tv_get_modes,
.cleanup = intel_tv_destroy, .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); 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->driver_private = intel_output;
output->interlace_allowed = FALSE; output->interlace_allowed = FALSE;
output->doublescan_allowed = FALSE; output->doublescan_allowed = FALSE;

View File

@ -13,6 +13,7 @@
#include "i915_drm.h" #include "i915_drm.h"
#include "i915_drv.h" #include "i915_drv.h"
#include "intel_bios.h" #include "intel_bios.h"
#include "intel_drv.h"
/** /**
* i915_probe_agp - get AGP bootup configuration * i915_probe_agp - get AGP bootup configuration
@ -232,7 +233,7 @@ int i915_load_modeset_init(struct drm_device *dev)
} }
intel_modeset_init(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_VRAM].manager, "VRAM");
drm_mm_print(&dev->bm.man[DRM_BO_MEM_TT].manager, "TT"); drm_mm_print(&dev->bm.man[DRM_BO_MEM_TT].manager, "TT");

View File

@ -31,6 +31,7 @@
#include "i915_drm.h" #include "i915_drm.h"
#include "i915_drv.h" #include "i915_drv.h"
#include "intel_drv.h" #include "intel_drv.h"
#include "drm_crtc_helper.h"
#define MAX_NOPID ((u32)~0) #define MAX_NOPID ((u32)~0)
@ -471,7 +472,7 @@ static void i915_hotplug_tv(struct drm_device *dev)
goto unlock; goto unlock;
status = output->funcs->detect(output); status = output->funcs->detect(output);
drm_hotplug_stage_two(dev, output, drm_helper_hotplug_stage_two(dev, output,
status == output_status_connected ? 1 : 0); status == output_status_connected ? 1 : 0);
unlock: unlock:
@ -497,7 +498,7 @@ static void i915_hotplug_crt(struct drm_device *dev, bool isconnected)
if (iout == 0) if (iout == 0)
goto unlock; goto unlock;
drm_hotplug_stage_two(dev, output, isconnected); drm_helper_hotplug_stage_two(dev, output, isconnected);
unlock: unlock:
mutex_unlock(&dev->mode_config.mutex); 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); status = output->funcs->detect(output);
if (status != output_status_connected) if (status != output_status_connected)
drm_hotplug_stage_two(dev, output, false); drm_helper_hotplug_stage_two(dev, output, false);
else else
drm_hotplug_stage_two(dev, output, true); drm_helper_hotplug_stage_two(dev, output, true);
intel_sdvo_set_hotplug(output, 1); intel_sdvo_set_hotplug(output, 1);