summaryrefslogtreecommitdiff
path: root/linux-core/drm_crtc.c
diff options
context:
space:
mode:
authorroot <root@localhost.(none)>2007-05-17 12:46:36 +0100
committerroot <root@localhost.(none)>2007-05-17 12:46:36 +0100
commit5ce8aaae7251e60c078eda0a21894aae0e1d7a45 (patch)
tree97855e1a7492e547445f2a56e84a3b70d8683108 /linux-core/drm_crtc.c
parenteba00df1203040905d38bf0ef449d25d6dbdb72c (diff)
Large changes for fbdev support.
Change from DIRECTCOLOR to TRUECOLOR, and enable support for PSEUDOCOLOR. DIRECTCOLOR support needs more work. Add the ability to change the mode on the fbdev device. Support depth 8, 15, 16 and 24 (and 32). Add a /dev/fbX device per CRTC, but there's some code which doesn't allocate the fbX device unless the output is actually enabled. Read the code on this as it impacts the fbcon map flags. Pick CRTC's based on the available outputs. More work could be done here to match modes, so cloning could be achieved on outputs. This fits more inline with what the X code does.
Diffstat (limited to 'linux-core/drm_crtc.c')
-rw-r--r--linux-core/drm_crtc.c234
1 files changed, 100 insertions, 134 deletions
diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c
index a8f14e17..d710a4e7 100644
--- a/linux-core/drm_crtc.c
+++ b/linux-core/drm_crtc.c
@@ -467,51 +467,6 @@ done:
}
/**
- * drm_set_desired_modes - set a good mode on every CRTC & output
- * @dev: DRM device
- *
- * LOCKING:
- * Caller? (FIXME)
- *
- * Each CRTC may have a desired mode associated with it. This routine simply
- * walks @dev's mode_config and sets the desired mode on every CRTC. Intended
- * for use at startup time.
- *
- * RETURNS:
- * True if modes were set, false otherwise.
- */
-bool drm_set_desired_modes(struct drm_device *dev)
-{
- struct drm_crtc *crtc;
- struct drm_output *output, *list_output;
-
- list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
- output = NULL;
-
- list_for_each_entry(list_output, &dev->mode_config.output_list,
- head) {
- if (list_output->crtc == crtc) {
- output = list_output;
- break;
- }
- }
- /* Skip disabled crtcs */
- if (!output) {
- DRM_DEBUG("skipping disabled crtc\n");
- continue;
- }
-
- if (!drm_crtc_set_mode(crtc, crtc->desired_mode,
- crtc->desired_x, crtc->desired_y))
- return false;
- }
-
- drm_disable_unused_functions(dev);
- return true;
-}
-EXPORT_SYMBOL(drm_set_desired_modes);
-
-/**
* drm_disable_unused_functions - disable unused objects
* @dev: DRM device
*
@@ -799,26 +754,82 @@ out_err:
}
/**
- * drm_setup_output - setup an output structure
- * @output: output to setup
- * @crtc: CRTC this output belongs to
- * @mode: desired mode for this output
+ * drm_pick_crtcs - pick crtcs for output devices
+ * @dev: DRM device
*
* LOCKING:
* None.
- *
- * Setup @output with the parameters given, with its initial coordinates set
- * at the origin.
*/
-static void drm_setup_output(struct drm_output *output, struct drm_crtc *crtc,
- struct drm_display_mode *mode)
+static void drm_pick_crtcs (drm_device_t *dev)
{
- output->crtc = crtc;
- output->crtc->desired_mode = mode;
- output->initial_x = 0;
- output->initial_y = 0;
+ int c, o;
+ struct drm_output *output, *output_equal;
+ struct drm_crtc *crtc;
+ struct drm_display_mode *des_mode = NULL, *modes, *modes_equal;
+
+ 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;
+
+ des_mode = NULL;
+ list_for_each_entry(des_mode, &output->modes, head) {
+ if (des_mode->flags & DRM_MODE_TYPE_PREFERRED)
+ break;
+ }
+
+ c = -1;
+ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+ c++;
+ if ((output->possible_crtcs & (1 << c)) == 0)
+ continue;
+
+#if 0 /* should we try and clone ?? - code not tested - FIXME */
+ 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 & (1 << o))) {
+ goto clone;
+ }
+ }
+ }
+ }
+ }
+
+clone:
+#endif
+ /* 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 %dx%x\n",c,des_mode->hdisplay,des_mode->vdisplay);
+ break;
+ }
+ }
}
+
/**
* drm_initial_config - setup a sane initial output configuration
* @dev: DRM device
@@ -831,109 +842,61 @@ static void drm_setup_output(struct drm_output *output, struct drm_crtc *crtc,
* At the moment, this is a cloned configuration across all heads with
* a new framebuffer object as the backing store.
*
- * FIXME: return value and better initial config.
- *
* RETURNS:
* Zero if everything went ok, nonzero otherwise.
*/
bool drm_initial_config(drm_device_t *dev, bool can_grow)
{
/* do a hardcoded initial configuration here */
- struct drm_crtc *crtc, *vga_crtc = NULL, *tmds_crtc = NULL,
- *lvds_crtc = NULL;
+ struct drm_display_mode *des_mode = NULL;
struct drm_output *output;
struct drm_framebuffer *fb;
drm_buffer_object_t *fbo;
unsigned long size, bytes_per_pixel;
- fb = drm_framebuffer_create(dev);
- if (!fb) {
- DRM_ERROR("failed to allocate fb.\n");
- return true;
- }
-
- /* bind both CRTCs to this fb */
- /* only initialise one crtc to enabled state */
- list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
- crtc->fb = fb;
- if (!vga_crtc) {
- vga_crtc = crtc;
- crtc->enabled = 1;
- crtc->desired_x = 0;
- crtc->desired_y = 0;
- } else {
- if (!lvds_crtc) {
- lvds_crtc = crtc;
- crtc->enabled = 1;
- crtc->desired_x = 0;
- crtc->desired_y = 0;
- }
- if (!tmds_crtc) {
- tmds_crtc = crtc;
- crtc->enabled = 1;
- crtc->desired_x = 0;
- crtc->desired_y = 0;
- }
- }
- }
-
drm_crtc_probe_output_modes(dev, 2048, 2048);
- /* hard bind the CRTCS */
+ drm_pick_crtcs(dev);
- /* bind analog output to one crtc */
list_for_each_entry(output, &dev->mode_config.output_list, head) {
- struct drm_display_mode *des_mode = NULL;
- if (list_empty(&output->modes))
+ /* can't setup the output if there's no assigned crtc or mode */
+ if (!output->crtc || !output->crtc->desired_mode)
continue;
- /* Get the first preferred moded */
- list_for_each_entry(des_mode, &output->modes, head) {
- if (des_mode->flags & DRM_MODE_TYPE_PREFERRED)
- break;
+ fb = drm_framebuffer_create(dev);
+ if (!fb) {
+ DRM_ERROR("failed to allocate fb.\n");
+ return true;
}
+ output->crtc->fb = fb;
+ des_mode = output->crtc->desired_mode;
- if (!des_mode)
- continue;
-
- if (!strncmp(output->name, "VGA", 3)) {
- DRM_DEBUG("VGA preferred mode: %s\n", des_mode->name);
- drm_setup_output(output, vga_crtc, des_mode);
- } else if (!strncmp(output->name, "TMDS", 4)) {
- DRM_DEBUG("TMDS preferred mode: %s\n", des_mode->name);
- drm_setup_output(output, tmds_crtc, des_mode);
- } else if (!strncmp(output->name, "LVDS", 3)) {
- DRM_DEBUG("LVDS preferred mode: %s\n", des_mode->name);
- drm_setup_output(output, lvds_crtc, des_mode);
- } else
- output->crtc = NULL;
-
- /* FB config is max of above desired resolutions */
- /* FIXME: per-output FBs/CRTCs */
if (des_mode->hdisplay > fb->width) {
fb->width = des_mode->hdisplay;
fb->pitch = fb->width;
}
if (des_mode->vdisplay > fb->height)
fb->height = des_mode->vdisplay;
- }
- /* FIXME: multiple depths */
- bytes_per_pixel = 4;
- fb->bits_per_pixel = bytes_per_pixel * 8;
- fb->depth = bytes_per_pixel * 8;
- size = fb->width * fb->height * bytes_per_pixel;
- drm_buffer_object_create(dev, size, drm_bo_type_kernel,
+ /* FIXME: multiple depths */
+ bytes_per_pixel = 4;
+ fb->bits_per_pixel = 32;
+ fb->depth = 24;
+ size = fb->pitch * fb->height * bytes_per_pixel;
+ /* FIXME - what about resizeable objects ??? */
+ drm_buffer_object_create(dev, size, drm_bo_type_kernel,
DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE |
DRM_BO_FLAG_MEM_PRIV0 | DRM_BO_FLAG_NO_MOVE,
0, 0, 0,
&fbo);
- DRM_DEBUG("allocated %dx%d fb: 0x%08lx, bo %p\n", fb->width,
- fb->height, fbo->offset, fbo);
- fb->offset = fbo->offset;
- fb->bo = fbo;
- drmfb_probe(dev, fb);
+ printk("allocated %dx%d fb: 0x%08lx, bo %p\n", fb->width,
+ fb->height, fbo->offset, fbo);
+ fb->offset = fbo->offset;
+ fb->bo = fbo;
+ drmfb_probe(dev, output->crtc);
+ }
+ drm_disable_unused_functions(dev);
return false;
}
@@ -1582,17 +1545,20 @@ int drm_mode_addfb(struct inode *inode, struct file *filp,
r.buffer_id = fb->id;
list_add(&fb->filp_head, &priv->fbs);
+
+ if (copy_to_user(argp, &r, sizeof(r)))
+ return -EFAULT;
+
/* bind the fb to the crtc for now */
{
struct drm_crtc *crtc;
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
crtc->fb = fb;
+
+ drmfb_probe(dev, crtc);
}
}
- if (copy_to_user(argp, &r, sizeof(r)))
- return -EFAULT;
- drmfb_probe(dev, fb);
return 0;
}
@@ -1629,6 +1595,7 @@ int drm_mode_rmfb(struct inode *inode, struct file *filp,
}
drmfb_remove(dev, fb);
+
/* TODO check if we own the buffer */
/* TODO release all crtc connected to the framebuffer */
/* bind the fb to the crtc for now */
@@ -1711,7 +1678,6 @@ void drm_fb_release(struct file *filp)
list_del(&fb->filp_head);
drmfb_remove(dev, fb);
drm_framebuffer_destroy(fb);
-
}
}