From eba00df1203040905d38bf0ef449d25d6dbdb72c Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Thu, 10 May 2007 13:16:05 +0100 Subject: Just some minor cleanups. --- linux-core/drm_fb.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'linux-core/drm_fb.c') diff --git a/linux-core/drm_fb.c b/linux-core/drm_fb.c index ef05341a..c0453258 100644 --- a/linux-core/drm_fb.c +++ b/linux-core/drm_fb.c @@ -106,8 +106,7 @@ int drmfb_probe(struct drm_device *dev, struct drm_framebuffer *fb) struct fb_info *info; struct drmfb_par *par; struct device *device = &dev->pdev->dev; - struct fb_var_screeninfo *var_info; - unsigned long base, size; + unsigned long size = (8*1024*1024); /* FIXME */ int ret; info = framebuffer_alloc(sizeof(struct drmfb_par), device); @@ -126,7 +125,7 @@ int drmfb_probe(struct drm_device *dev, struct drm_framebuffer *fb) strcpy(info->fix.id, "drmfb"); info->fix.smem_start = fb->offset + dev->mode_config.fb_base; - info->fix.smem_len = (8*1024*1024); + info->fix.smem_len = size; info->fix.type = FB_TYPE_PACKED_PIXELS; info->fix.visual = FB_VISUAL_DIRECTCOLOR; info->fix.accel = FB_ACCEL_NONE; -- cgit v1.2.3 From 5ce8aaae7251e60c078eda0a21894aae0e1d7a45 Mon Sep 17 00:00:00 2001 From: root Date: Thu, 17 May 2007 12:46:36 +0100 Subject: 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. --- linux-core/drm_fb.c | 267 ++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 248 insertions(+), 19 deletions(-) (limited to 'linux-core/drm_fb.c') diff --git a/linux-core/drm_fb.c b/linux-core/drm_fb.c index c0453258..8fd0f620 100644 --- a/linux-core/drm_fb.c +++ b/linux-core/drm_fb.c @@ -39,9 +39,11 @@ #include #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; } -- cgit v1.2.3 From 2222bd767f9fc02d05ebd0f35a8ceeff2f032c94 Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Thu, 17 May 2007 13:19:56 +0100 Subject: Fix build problem --- linux-core/drm_fb.c | 1 + 1 file changed, 1 insertion(+) (limited to 'linux-core/drm_fb.c') diff --git a/linux-core/drm_fb.c b/linux-core/drm_fb.c index 8fd0f620..27d80d7a 100644 --- a/linux-core/drm_fb.c +++ b/linux-core/drm_fb.c @@ -92,6 +92,7 @@ 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_framebuffer *fb = par->crtc->fb; struct drm_display_mode *drm_mode; struct drm_output *output; int depth; -- cgit v1.2.3 From fd63ea971322246734fca5977a800c3ef51cc3fe Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Thu, 17 May 2007 17:00:11 +0100 Subject: Grab the default mode if the preferred mode isn't available. Fix an overflow problem. --- linux-core/drm_fb.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'linux-core/drm_fb.c') diff --git a/linux-core/drm_fb.c b/linux-core/drm_fb.c index 27d80d7a..118967bf 100644 --- a/linux-core/drm_fb.c +++ b/linux-core/drm_fb.c @@ -351,7 +351,9 @@ int drmfb_probe(struct drm_device *dev, struct drm_crtc *crtc) 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; + mode->vtotal * 100; + /* avoid overflow */ + info->var.pixclock = info->var.pixclock * 1000 / mode->vrefresh; DRM_DEBUG("fb depth is %d\n", fb->depth); switch(fb->depth) { -- cgit v1.2.3