OSDN Git Service

Large changes for fbdev support.
authorroot <root@localhost.(none)>
Thu, 17 May 2007 11:46:36 +0000 (12:46 +0100)
committerroot <root@localhost.(none)>
Thu, 17 May 2007 11:46:36 +0000 (12:46 +0100)
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.

linux-core/drm_crtc.c
linux-core/drm_crtc.h
linux-core/drm_fb.c
linux-core/intel_display.c
linux-core/intel_drv.h
linux-core/intel_lvds.c
linux-core/intel_sdvo.c

index a8f14e1..d710a4e 100644 (file)
@@ -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);
-               
        }
 }
 
index 12c7eef..fa143e6 100644 (file)
@@ -294,8 +294,8 @@ struct drm_crtc_funcs {
        void (*mode_set)(struct drm_crtc *crtc, struct drm_display_mode *mode,
                         struct drm_display_mode *adjusted_mode, int x, int y);
        /* Set gamma on the CRTC */
-       void (*gamma_set)(struct drm_crtc *crtc, u16 *r, u16 *g, u16 *b,
-                         int size);
+       void (*gamma_set)(struct drm_crtc *crtc, u16 r, u16 g, u16 b,
+                         int regno);
        /* Driver cleanup routine */
        void (*cleanup)(struct drm_crtc *crtc);
 };
@@ -320,7 +320,7 @@ struct drm_crtc {
 
        int id; /* idr assigned */
 
-       /* framebuffer the CRTC is currently bound to */
+       /* framebuffer the output is currently bound to */
        struct drm_framebuffer *fb;
 
        bool enabled;
@@ -439,6 +439,7 @@ struct drm_output {
        void *driver_private;
 
        u32 user_mode_ids[DRM_OUTPUT_MAX_UMODES];
+
 };
 
 /**
@@ -498,6 +499,7 @@ extern void drm_mode_debug_printmodeline(struct drm_device *dev,
 extern void drm_mode_config_init(struct drm_device *dev);
 extern void drm_mode_config_cleanup(struct drm_device *dev);
 extern void drm_mode_set_name(struct drm_display_mode *mode);
+extern bool drm_mode_equal(struct drm_display_mode *mode1, struct drm_display_mode *mode2);
 extern void drm_disable_unused_functions(struct drm_device *dev);
 
 extern struct drm_display_mode *drm_mode_create(struct drm_device *dev);
@@ -519,8 +521,7 @@ 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 bool drm_set_desired_modes(struct drm_device *dev);
-extern int drmfb_probe(struct drm_device *dev, 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);
 
 /* IOCTLs */
index c045325..8fd0f62 100644 (file)
 #include <linux/init.h>
 
 #include "drmP.h"
+#include "drm_crtc.h"
+
 struct drmfb_par {
        struct drm_device *dev;
-       struct drm_framebuffer *fb;
+       struct drm_crtc *crtc;
 };
 
 static int drmfb_setcolreg(unsigned regno, unsigned red, unsigned green,
@@ -49,11 +51,20 @@ static int drmfb_setcolreg(unsigned regno, unsigned red, unsigned green,
                           struct fb_info *info)
 {
        struct drmfb_par *par = info->par;
-       struct drm_framebuffer *fb = par->fb;
-       if (regno > 17)
+       struct drm_framebuffer *fb = par->crtc->fb;
+       struct drm_crtc *crtc = par->crtc;
+
+       if (regno > 255)
                return 1;
 
-       if (regno < 16) {
+       if (fb->depth == 8) {
+               if (crtc->funcs->gamma_set) {
+                       crtc->funcs->gamma_set(crtc, red, green, blue, regno);
+               }
+               return 0;
+       }
+       
+       if (regno < 16) {
                switch (fb->depth) {
                case 15:
                        fb->pseudo_palette[regno] = ((red & 0xf800) >>  1) |
@@ -72,8 +83,118 @@ static int drmfb_setcolreg(unsigned regno, unsigned red, unsigned green,
                                ((blue  & 0xff00) >> 8);
                        break;
                }
+        }
+
+       return 0;
+}
+
+static int drmfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+       struct drmfb_par *par = info->par;
+       struct drm_device *dev = par->dev;
+       struct drm_display_mode *drm_mode;
+       struct drm_output *output;
+       int depth;
+
+       if (!var->pixclock)
+               return -EINVAL;
+
+       /* Need to resize the fb object !!! */
+       if (var->xres > fb->width || var->yres > fb->height) {
+               DRM_ERROR("Requested width/height is greater than current fb object %dx%d > %dx%d\n",var->xres,var->yres,fb->width,fb->height);
+               DRM_ERROR("Need resizing code.\n");
+               return -EINVAL;
+       }
+
+       switch (var->bits_per_pixel) {
+       case 16:
+               depth = (var->green.length == 6) ? 16 : 15;
+               break;
+       case 32:
+               depth = (var->transp.length > 0) ? 32 : 24;
+               break;
+       default:
+               depth = var->bits_per_pixel;
+               break;
+       }
+               
+       switch (depth) {
+       case 8:
+               var->red.offset = 0;
+               var->green.offset = 0;
+               var->blue.offset = 0;
+               var->red.length = 8;
+               var->green.length = 8;
+               var->blue.length = 8;
+               var->transp.length = 0;
+               var->transp.offset = 0;
+               break;
+       case 15:
+               var->red.offset = 10;
+               var->green.offset = 5;
+               var->blue.offset = 0;
+               var->red.length = 5;
+               var->green.length = 5;
+               var->blue.length = 5;
+               var->transp.length = 1;
+               var->transp.offset = 15;
+               break;
+       case 16:
+               var->red.offset = 11;
+               var->green.offset = 6;
+               var->blue.offset = 0;
+               var->red.length = 5;
+               var->green.length = 6;
+               var->blue.length = 5;
+               var->transp.length = 0;
+               var->transp.offset = 0;
+               break;
+       case 24:
+               var->red.offset = 16;
+               var->green.offset = 8;
+               var->blue.offset = 0;
+               var->red.length = 8;
+               var->green.length = 8;
+               var->blue.length = 8;
+               var->transp.length = 0;
+               var->transp.offset = 0;
+               break;
+       case 32:
+               var->red.offset = 16;
+               var->green.offset = 8;
+               var->blue.offset = 0;
+               var->red.length = 8;
+               var->green.length = 8;
+               var->blue.length = 8;
+               var->transp.length = 8;
+               var->transp.offset = 24;
+               break;
+       default:
+               return -EINVAL; 
+       }
+
+#if 0
+       /* Here we walk the output mode list and look for modes. If we haven't
+        * got it, then bail. Not very nice, so this is disabled.
+        * In the set_par code, we create our mode based on the incoming
+        * parameters. Nicer, but may not be desired by some.
+        */
+       list_for_each_entry(output, &dev->mode_config.output_list, head) {
+               if (output->crtc == par->crtc)
+                       break;
+       }
+    
+       list_for_each_entry(drm_mode, &output->modes, head) {
+               if (drm_mode->hdisplay == var->xres &&
+                   drm_mode->vdisplay == var->yres &&
+                   drm_mode->clock != 0)
+                   break;
        }
 
+       if (!drm_mode)
+               return -EINVAL;
+#endif
+
        return 0;
 }
 
@@ -81,9 +202,74 @@ static int drmfb_setcolreg(unsigned regno, unsigned red, unsigned green,
 static int drmfb_set_par(struct fb_info *info)
 {
        struct drmfb_par *par = info->par;
+       struct drm_framebuffer *fb = par->crtc->fb;
        struct drm_device *dev = par->dev;
+       struct drm_display_mode *drm_mode;
+       struct fb_var_screeninfo *var = &info->var;
+       struct drm_output *output;
+
+       switch (var->bits_per_pixel) {
+       case 16:
+               fb->depth = (var->green.length == 6) ? 16 : 15;
+               break;
+       case 32:
+               fb->depth = (var->transp.length > 0) ? 32 : 24;
+               break;
+       default:
+               fb->depth = var->bits_per_pixel;
+               break;
+       }
+
+       fb->bits_per_pixel = var->bits_per_pixel;
+
+       info->fix.line_length = fb->pitch * ((fb->bits_per_pixel + 1) / 8);
+       info->fix.smem_len = info->fix.line_length * fb->height;
+       info->fix.visual = (fb->depth == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
+
+       info->screen_size = info->fix.smem_len; /* ??? */
+
+       /* Should we walk the output's modelist or just create our own ???
+        * For now, we create and destroy a mode based on the incoming 
+        * parameters. But there's commented out code below which scans 
+        * the output list too.
+        */
+#if 0
+       list_for_each_entry(output, &dev->mode_config.output_list, head) {
+               if (output->crtc == par->crtc)
+                       break;
+       }
+    
+       list_for_each_entry(drm_mode, &output->modes, head) {
+               if (drm_mode->hdisplay == var->xres &&
+                   drm_mode->vdisplay == var->yres &&
+                   drm_mode->clock != 0)
+                   break;
+       }
+#else
+       drm_mode = drm_mode_create(dev);
+       drm_mode->hdisplay = var->xres;
+       drm_mode->hsync_start = drm_mode->hdisplay + var->right_margin;
+       drm_mode->hsync_end = drm_mode->hsync_start + var->hsync_len;
+       drm_mode->htotal = drm_mode->hsync_end + var->left_margin;
+       drm_mode->vdisplay = var->yres;
+       drm_mode->vsync_start = drm_mode->vdisplay + var->lower_margin;
+       drm_mode->vsync_end = drm_mode->vsync_start + var->vsync_len;
+       drm_mode->vtotal = drm_mode->vsync_end + var->upper_margin;
+       drm_mode->clock = PICOS2KHZ(var->pixclock);
+       drm_mode->vrefresh = drm_mode_vrefresh(drm_mode);
+       drm_mode_set_name(drm_mode);
+#endif
+
+       if (!drm_crtc_set_mode(par->crtc, drm_mode, 0, 0))
+               return -EINVAL;
+
+       /* Have to destroy our created mode if we're not searching the mode
+        * list for it.
+        */
+#if 1 
+       drm_mode_destroy(dev, drm_mode);
+#endif
 
-       drm_set_desired_modes(dev);
        return 0;
 }
 
@@ -94,6 +280,7 @@ static struct fb_ops drmfb_ops = {
        //      .fb_write = drmfb_write,
        //      .fb_release = drmfb_release,
        //      .fb_ioctl = drmfb_ioctl,
+       .fb_check_var = drmfb_check_var,
        .fb_set_par = drmfb_set_par,
        .fb_setcolreg = drmfb_setcolreg,
        .fb_fillrect = cfb_fillrect,
@@ -101,12 +288,13 @@ static struct fb_ops drmfb_ops = {
        .fb_imageblit = cfb_imageblit,
 };
 
-int drmfb_probe(struct drm_device *dev, struct drm_framebuffer *fb)
+int drmfb_probe(struct drm_device *dev, struct drm_crtc *crtc)
 {
        struct fb_info *info;
+       struct drm_framebuffer *fb = crtc->fb;
        struct drmfb_par *par;
        struct device *device = &dev->pdev->dev; 
-       unsigned long size = (8*1024*1024); /* FIXME */
+       struct drm_display_mode *mode = crtc->desired_mode;
        int ret;
 
        info = framebuffer_alloc(sizeof(struct drmfb_par), device);
@@ -119,20 +307,20 @@ int drmfb_probe(struct drm_device *dev, struct drm_framebuffer *fb)
        par = info->par;
 
        par->dev = dev;
-       par->fb = fb;
+       par->crtc = crtc;
 
        info->fbops = &drmfb_ops;
 
        strcpy(info->fix.id, "drmfb");
-       info->fix.smem_start = fb->offset + dev->mode_config.fb_base;
-       info->fix.smem_len = size;
        info->fix.type = FB_TYPE_PACKED_PIXELS;
-       info->fix.visual = FB_VISUAL_DIRECTCOLOR;
+       info->fix.visual = FB_VISUAL_TRUECOLOR;
        info->fix.accel = FB_ACCEL_NONE;
        info->fix.type_aux = 0;
        info->fix.mmio_start = 0;
        info->fix.mmio_len = 0;
        info->fix.line_length = fb->pitch * ((fb->bits_per_pixel + 1) / 8);
+       info->fix.smem_start = fb->offset + dev->mode_config.fb_base;
+       info->fix.smem_len = info->fix.line_length * fb->height;
 
        info->flags = FBINFO_DEFAULT;
 
@@ -141,11 +329,9 @@ int drmfb_probe(struct drm_device *dev, struct drm_framebuffer *fb)
                DRM_ERROR("error mapping fb: %d\n", ret);
 
        info->screen_base = fb->virtual_base;
-       info->screen_size = size;
+       info->screen_size = info->fix.smem_len; /* ??? */
        info->pseudo_palette = fb->pseudo_palette;
-       info->var.xres = fb->width;
        info->var.xres_virtual = fb->pitch;
-       info->var.yres = fb->height;
        info->var.yres_virtual = fb->height;
        info->var.bits_per_pixel = fb->bits_per_pixel;
        info->var.xoffset = 0;
@@ -155,24 +341,67 @@ int drmfb_probe(struct drm_device *dev, struct drm_framebuffer *fb)
        info->var.width = -1;
        info->var.vmode = FB_VMODE_NONINTERLACED;
 
+       info->var.xres = mode->hdisplay;
+       info->var.right_margin = mode->hsync_start - mode->hdisplay;
+       info->var.hsync_len = mode->hsync_end - mode->hsync_start;
+       info->var.left_margin = mode->htotal - mode->hsync_end;
+       info->var.yres = mode->vdisplay;
+       info->var.lower_margin = mode->vsync_start - mode->vdisplay;
+       info->var.vsync_len = mode->vsync_end - mode->vsync_start;
+       info->var.upper_margin = mode->vtotal - mode->vsync_end;
+       info->var.pixclock = 10000000 / mode->htotal * 1000 /
+                               mode->vtotal * 100000 / mode->vrefresh;
+
        DRM_DEBUG("fb depth is %d\n", fb->depth);
        switch(fb->depth) {
        case 8:
+               info->var.red.offset = 0;
+               info->var.green.offset = 0;
+               info->var.blue.offset = 0;
+               info->var.red.length = 8; /* 8bit DAC */
+               info->var.green.length = 8;
+               info->var.blue.length = 8;
+               info->var.transp.offset = 0;
+               info->var.transp.length = 0;
+               break;
        case 15:
+               info->var.red.offset = 10;
+               info->var.green.offset = 5;
+               info->var.blue.offset = 0;
+               info->var.red.length = info->var.green.length =
+                       info->var.blue.length = 5;
+               info->var.transp.offset = 15;
+               info->var.transp.length = 1;
+               break;
        case 16:
+               info->var.red.offset = 11;
+               info->var.green.offset = 5;
+               info->var.blue.offset = 0;
+               info->var.red.length = 5;
+               info->var.green.length = 6;
+               info->var.blue.length = 5;
+               info->var.transp.offset = 0;
+               info->var.transp.length = 0;
                break;
-       default:
        case 24:
+               info->var.red.offset = 16;
+               info->var.green.offset = 8;
+               info->var.blue.offset = 0;
+               info->var.red.length = info->var.green.length =
+                       info->var.blue.length = 8;
+               info->var.transp.offset = 0;
+               info->var.transp.length = 0;
+               break;
        case 32:
                info->var.red.offset = 16;
                info->var.green.offset = 8;
                info->var.blue.offset = 0;
                info->var.red.length = info->var.green.length =
                        info->var.blue.length = 8;
-               if (fb->depth == 32) {
-                       info->var.transp.offset = 24;
-                       info->var.transp.length = 8;
-               }
+               info->var.transp.offset = 24;
+               info->var.transp.length = 8;
+               break;
+       default:
                break;
        }
 
index 7d58117..7879965 100644 (file)
@@ -787,6 +787,9 @@ static void intel_crtc_mode_set(struct drm_crtc *crtc,
        else
                dpll |= PLL_REF_INPUT_DREFCLK;
        
+       /* setup pipeconf */
+       pipeconf = I915_READ(pipeconf_reg);
+
        /* Set up the display plane register */
        dspcntr = DISPPLANE_GAMMA_ENABLE;
 
@@ -814,7 +817,6 @@ static void intel_crtc_mode_set(struct drm_crtc *crtc,
        else
                dspcntr |= DISPPLANE_SEL_PIPE_B;
        
-       pipeconf = I915_READ(pipeconf_reg);
        if (pipe == 0 && !IS_I965G(dev)) {
                /* Enable pixel doubling when the dot clock is > 90% of the (display)
                 * core speed.
@@ -955,19 +957,14 @@ void intel_crtc_load_lut(struct drm_crtc *crtc)
 }
 
 /** Sets the color ramps on behalf of RandR */
-static void intel_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green,
-                                u16 *blue, int size)
+static void intel_crtc_gamma_set(struct drm_crtc *crtc, u16 red, u16 green,
+                                u16 blue, int regno)
 {
        struct intel_crtc *intel_crtc = crtc->driver_private;
-       int i;
        
-       for (i = 0; i < 256; i++) {
-               intel_crtc->lut_r[i] = red[i] >> 8;
-               intel_crtc->lut_g[i] = green[i] >> 8;
-               intel_crtc->lut_b[i] = blue[i] >> 8;
-       }
-       
-       intel_crtc_load_lut(crtc);
+       intel_crtc->lut_r[regno] = red >> 8;
+       intel_crtc->lut_g[regno] = green >> 8;
+       intel_crtc->lut_b[regno] = blue >> 8;
 }
 
 /* Returns the clock of the currently programmed mode of the given pipe. */
@@ -1176,7 +1173,8 @@ static void intel_setup_outputs(drm_device_t *dev)
                                      (1 << INTEL_OUTPUT_SDVO));
                        break;
                case INTEL_OUTPUT_ANALOG:
-                       crtc_mask = ((1 << 0));
+                       crtc_mask = ((1 << 0)|
+                                    (1 << 1));
                        clone_mask = ((1 << INTEL_OUTPUT_ANALOG) |
                                      (1 << INTEL_OUTPUT_DVO) |
                                      (1 << INTEL_OUTPUT_SDVO));
@@ -1223,7 +1221,6 @@ void intel_modeset_init(drm_device_t *dev)
        intel_setup_outputs(dev);
 
        //drm_initial_config(dev, false);
-       //drm_set_desired_modes(dev);
 }
 
 void intel_modeset_cleanup(drm_device_t *dev)
index aa33437..fdf260e 100644 (file)
@@ -72,7 +72,7 @@ extern void intel_crtc_load_lut(struct drm_crtc *crtc);
 extern void intel_output_prepare (struct drm_output *output);
 extern void intel_output_commit (struct drm_output *output);
 extern struct drm_display_mode *intel_crtc_mode_get(drm_device_t *dev,
-                                                   struct drm_crtc *crtc);
+                                                   struct drm_crtc *crtc);
 extern void intel_wait_for_vblank(drm_device_t *dev);
 extern struct drm_crtc *intel_get_crtc_from_pipe(drm_device_t *dev, int pipe);
 
index 74b040b..942eb2a 100644 (file)
@@ -164,6 +164,13 @@ static bool intel_lvds_mode_fixup(struct drm_output *output,
        struct intel_crtc *intel_crtc = output->crtc->driver_private;
        struct drm_output *tmp_output;
 
+       /* Should never happen!! */
+       if (!IS_I965G(dev) && intel_crtc->pipe == 0) {
+               printk(KERN_ERR "Can't support LVDS on pipe A\n");
+               return false;
+       }
+
+       /* Should never happen!! */
        list_for_each_entry(tmp_output, &dev->mode_config.output_list, head) {
                if (tmp_output != output && tmp_output->crtc == output->crtc) {
                        printk(KERN_ERR "Can't enable LVDS and another "
@@ -172,11 +179,6 @@ static bool intel_lvds_mode_fixup(struct drm_output *output,
                }
        }
 
-       if (intel_crtc->pipe == 0) {
-               printk(KERN_ERR "Can't support LVDS on pipe A\n");
-               return false;
-       }
-
        /*
         * If we have timings from the BIOS for the panel, put them in
         * to the adjusted mode.  The CRTC will be set up for this mode,
index 58aa432..c02fd95 100644 (file)
@@ -1010,26 +1010,18 @@ void intel_sdvo_init(drm_device_t *dev, int output_device)
 
        memset(&sdvo_priv->active_outputs, 0, sizeof(sdvo_priv->active_outputs));
 
-       /* TODO, CVBS, SVID, YPRPB & SCART outputs.
-        * drm_initial_config probably wants tweaking too to support the
-        * above. But has fixed VGA, TMDS and LVDS checking code. That should
-        * be dealt with.
-        */
+       /* TODO, CVBS, SVID, YPRPB & SCART outputs. */
        if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_RGB0)
        {
                sdvo_priv->active_outputs = SDVO_OUTPUT_RGB0;
                output->subpixel_order = SubPixelHorizontalRGB;
-               /* drm_initial_config wants this name, but should be RGB */
-               /* Use this for now.... */
-               name_prefix="VGA";
+               name_prefix="RGB";
        }
        else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_RGB1)
        {
                sdvo_priv->active_outputs = SDVO_OUTPUT_RGB1;
                output->subpixel_order = SubPixelHorizontalRGB;
-               /* drm_initial_config wants this name, but should be RGB */
-               /* Use this for now.... */
-               name_prefix="VGA";
+               name_prefix="RGB";
        }
        else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_TMDS0)
        {