diff --git a/drivers/video/aty/radeon_accel.c b/drivers/video/aty/radeon_accel.c --- a/drivers/video/aty/radeon_accel.c +++ b/drivers/video/aty/radeon_accel.c @@ -48,7 +48,7 @@ static void radeonfb_prim_fillrect(struc rinfo->dp_gui_master_cntl /* contains, like GMC_DST_32BPP */ | GMC_BRUSH_SOLID_COLOR | ROP3_P); - if (radeon_get_dstbpp(rinfo->depth) != DST_8BPP) + if ((rinfo->format == PIX_WIDTH_I4) || (rinfo->format == PIX_WIDTH_I8) || (rinfo->format == PIX_WIDTH_A8I8)) OUTREG(DP_BRUSH_FRGD_CLR, rinfo->pseudo_palette[region->color]); else OUTREG(DP_BRUSH_FRGD_CLR, region->color); @@ -252,8 +252,6 @@ void radeonfb_engine_reset(struct radeon void radeonfb_engine_init (struct radeonfb_info *rinfo) { - unsigned long temp; - /* disable 3D engine */ OUTREG(RB3D_CNTL, 0); @@ -287,8 +285,7 @@ void radeonfb_engine_init (struct radeon OUTREG(DEFAULT_SC_BOTTOM_RIGHT, (DEFAULT_SC_RIGHT_MAX | DEFAULT_SC_BOTTOM_MAX)); - temp = radeon_get_dstbpp(rinfo->depth); - rinfo->dp_gui_master_cntl = ((temp << 8) | GMC_CLR_CMP_CNTL_DIS); + rinfo->dp_gui_master_cntl = ((rinfo->format << 8) | GMC_CLR_CMP_CNTL_DIS); radeon_fifo_wait (1); OUTREG(DP_GUI_MASTER_CNTL, (rinfo->dp_gui_master_cntl | diff --git a/drivers/video/aty/radeon_base.c b/drivers/video/aty/radeon_base.c --- a/drivers/video/aty/radeon_base.c +++ b/drivers/video/aty/radeon_base.c @@ -722,99 +722,124 @@ static int radeonfb_check_var (struct fb { struct radeonfb_info *rinfo = info->par; struct fb_var_screeninfo v; - int nom, den; + int nom = 0, den = 0; unsigned int pitch; if (radeon_match_mode(rinfo, &v, var)) return -EINVAL; + v.red.offset = v.green.offset = v.blue.offset = 0; + v.red.length = v.blue.length = 0; + v.transp.offset = v.transp.length = 0; + switch (v.bits_per_pixel) { - case 0 ... 8: - v.bits_per_pixel = 8; + case 4: + nom = 1; + den = 2; + v.red.length = v.green.length = v.blue.length = 4; + rinfo->format = PIX_WIDTH_I4; + break; + case 8: + nom = den = 1; + v.red.length = v.green.length = v.blue.length = 8; + rinfo->format = PIX_WIDTH_I8; + break; + case 16: + nom = 2; + den = 1; + switch (v.green.length) { + case 4: + v.transp.offset = 12; + v.red.offset = 8; + v.green.offset = v.red.length = v.blue.length = v.transp.length = 4; + rinfo->format = PIX_WIDTH_A4R4B4G4; break; - case 9 ... 16: - v.bits_per_pixel = 16; + case 5: + v.red.offset = 10; + v.green.offset = 5; + v.transp.offset = 15; + v.red.length = v.blue.length = 5; + v.transp.length = 1; + rinfo->format = PIX_WIDTH_A1R5G5B5; break; - case 17 ... 24: -#if 0 /* Doesn't seem to work */ - v.bits_per_pixel = 24; + case 6: + v.red.offset = 11; + v.green.offset = 5; + v.red.length = 5; + v.blue.length = 5; + rinfo->format = PIX_WIDTH_R5G6B5; break; -#endif - return -EINVAL; - case 25 ... 32: - v.bits_per_pixel = 32; + case 0: + case 8: + v.transp.offset = 8; + v.red.length = v.green.length = v.blue.length = 8; + v.transp.length = 8; + rinfo->format = PIX_WIDTH_A8I8; break; default: - return -EINVAL; - } - - switch (var_to_depth(&v)) { - case 8: - nom = den = 1; - v.red.offset = v.green.offset = v.blue.offset = 0; - v.red.length = v.green.length = v.blue.length = 8; - v.transp.offset = v.transp.length = 0; - break; - case 15: - nom = 2; - den = 1; - v.red.offset = 10; - v.green.offset = 5; - v.blue.offset = 0; - v.red.length = v.green.length = v.blue.length = 5; - v.transp.offset = v.transp.length = 0; + goto err; + } + break; + case 24: + nom = 3; + den = 1; + v.red.offset = 16; + v.green.offset = 8; + v.blue.offset = 0; + v.red.length = v.blue.length = v.green.length = 8; + rinfo->format = PIX_WIDTH_R8B8G8; + break; + case 32: + nom = 4; + den = 1; + switch (v.green.length) { + case 10: + v.red.offset = 20; + v.green.offset = 10; + v.transp.offset = 30; + v.blue.length = v.red.length = 10; + v.transp.length = 2; + rinfo->format = PIX_WIDTH_A2R10G10B10; break; - case 16: - nom = 2; - den = 1; - v.red.offset = 11; - v.green.offset = 5; - v.blue.offset = 0; - v.red.length = 5; - v.green.length = 6; - v.blue.length = 5; - v.transp.offset = v.transp.length = 0; - break; - case 24: - nom = 4; - den = 1; - v.red.offset = 16; - v.green.offset = 8; - v.blue.offset = 0; - v.red.length = v.blue.length = v.green.length = 8; - v.transp.offset = v.transp.length = 0; - break; - case 32: - nom = 4; - den = 1; - v.red.offset = 16; - v.green.offset = 8; - v.blue.offset = 0; - v.red.length = v.blue.length = v.green.length = 8; - v.transp.offset = 24; - v.transp.length = 8; - break; - default: - printk ("radeonfb: mode %dx%dx%d rejected, color depth invalid\n", - var->xres, var->yres, var->bits_per_pixel); - return -EINVAL; - } + case 0: + case 8: + v.red.offset = 16; + v.green.offset = 8; + v.transp.offset = 24; + v.blue.length = v.red.length = 8; + v.transp.length = 8; + rinfo->format = PIX_WIDTH_A8R8G8B8; + break; + default: + goto err; + } + break; + default: +err: + printk ("radeonfb: mode %dx%dx%d rejected, color depth invalid\n", + var->xres, var->yres, var->bits_per_pixel); + return -EINVAL; + } if (v.yres_virtual < v.yres) v.yres_virtual = v.yres; if (v.xres_virtual < v.xres) v.xres_virtual = v.xres; - /* XXX I'm adjusting xres_virtual to the pitch, that may help XFree * with some panels, though I don't quite like this solution */ - if (rinfo->info->flags & FBINFO_HWACCEL_DISABLED) { + if (rinfo->info->flags & FBINFO_HWACCEL_DISABLED) { v.xres_virtual = v.xres_virtual & ~7ul; } else { - pitch = ((v.xres_virtual * ((v.bits_per_pixel + 1) / 8) + 0x3f) - & ~(0x3f)) >> 6; - v.xres_virtual = (pitch << 6) / ((v.bits_per_pixel + 1) / 8); + if (v.bits_per_pixel < 8) { + pitch = ((v.xres_virtual * (v.bits_per_pixel / 2) + 0x3f) & ~(0x3f)) >> 6; + v.xres_virtual = (pitch << 6) * 2; + } else { + pitch = ((v.xres_virtual * ((v.bits_per_pixel + 1) / 8) + 0x3f) + & ~(0x3f)) >> 6; + v.xres_virtual = (pitch << 6) / ((v.bits_per_pixel + 1) / 8); + } } if (((v.xres_virtual * v.yres_virtual * nom) / den) > rinfo->mapped_vram) @@ -824,21 +849,20 @@ static int radeonfb_check_var (struct fb v.xres = v.xres_virtual; if (v.xoffset < 0) - v.xoffset = 0; - if (v.yoffset < 0) - v.yoffset = 0; - - if (v.xoffset > v.xres_virtual - v.xres) - v.xoffset = v.xres_virtual - v.xres - 1; - - if (v.yoffset > v.yres_virtual - v.yres) - v.yoffset = v.yres_virtual - v.yres - 1; - - v.red.msb_right = v.green.msb_right = v.blue.msb_right = - v.transp.offset = v.transp.length = - v.transp.msb_right = 0; - - memcpy(var, &v, sizeof(v)); + v.xoffset = 0; + if (v.yoffset < 0) + v.yoffset = 0; + + if (v.xoffset > v.xres_virtual - v.xres) + v.xoffset = v.xres_virtual - v.xres - 1; + + if (v.yoffset > v.yres_virtual - v.yres) + v.yoffset = v.yres_virtual - v.yres - 1; + + v.red.msb_right = v.green.msb_right = v.blue.msb_right = + v.transp.msb_right = 0; + + memcpy(var, &v, sizeof(v)); return 0; } @@ -1554,7 +1578,7 @@ static int radeonfb_set_par(struct fb_in int nopllcalc = 0; int hsync_start, hsync_fudge, bytpp, hsync_wid, vsync_wid; int primary_mon = PRIMARY_MONITOR(rinfo); - int depth = var_to_depth(mode); + int depth = mode->bits_per_pixel; int use_rmx = 0; newmode = kmalloc(sizeof(struct radeon_regs), GFP_KERNEL); @@ -1630,7 +1654,7 @@ static int radeonfb_set_par(struct fb_in cSync = mode->sync & FB_SYNC_COMP_HIGH_ACT ? (1 << 4) : 0; - format = radeon_get_dstbpp(depth); + format = rinfo->format; bytpp = mode->bits_per_pixel >> 3; if ((primary_mon == MT_DFP) || (primary_mon == MT_LCD)) @@ -1676,11 +1700,19 @@ static int radeonfb_set_par(struct fb_in if (!(info->flags & FBINFO_HWACCEL_DISABLED)) { /* We first calculate the engine pitch */ - rinfo->pitch = ((mode->xres_virtual * ((mode->bits_per_pixel + 1) / 8) + 0x3f) + if (mode->bits_per_pixel < 8) { + rinfo->pitch = ((mode->xres_virtual / 2 + 0x3f) & ~(0x3f)) >> 6; - /* Then, re-multiply it to get the CRTC pitch */ - newmode->crtc_pitch = (rinfo->pitch << 3) / ((mode->bits_per_pixel + 1) / 8); + /* Then, re-multiply it to get the CRTC pitch */ + newmode->crtc_pitch = (rinfo->pitch << 3) * 2; + } else { + rinfo->pitch = ((mode->xres_virtual * ((mode->bits_per_pixel + 1) / 8) + 0x3f) + & ~(0x3f)) >> 6; + + /* Then, re-multiply it to get the CRTC pitch */ + newmode->crtc_pitch = (rinfo->pitch << 3) / ((mode->bits_per_pixel + 1) / 8); + } } else newmode->crtc_pitch = (mode->xres_virtual >> 3); @@ -1859,6 +1891,10 @@ static int radeonfb_set_par(struct fb_in return 0; } +char *radeonfb_getconfigs(struct fb_info *info) +{ + return "I4\nI8\nA1R5G5B5\nR5G6B5\nR8G8B8\nA8R8G8B8\nA4R4G4B4\nA8I8\nA2R10G10B10\n"; +} static struct fb_ops radeonfb_ops = { .owner = THIS_MODULE, @@ -1873,6 +1909,7 @@ static struct fb_ops radeonfb_ops = { .fb_fillrect = radeonfb_fillrect, .fb_copyarea = radeonfb_copyarea, .fb_imageblit = radeonfb_imageblit, + .fb_get_configs = radeonfb_getconfigs, }; diff --git a/drivers/video/aty/radeonfb.h b/drivers/video/aty/radeonfb.h --- a/drivers/video/aty/radeonfb.h +++ b/drivers/video/aty/radeonfb.h @@ -328,6 +328,7 @@ struct radeonfb_info { u32 dp_gui_master_cntl; struct pll_info pll; + unsigned int format; /* format of the scanout buffer */ int mtrr_hdl; @@ -511,29 +512,6 @@ static inline int round_div(int num, int return (num + (den / 2)) / den; } -static inline int var_to_depth(const struct fb_var_screeninfo *var) -{ - if (var->bits_per_pixel != 16) - return var->bits_per_pixel; - return (var->green.length == 5) ? 15 : 16; -} - -static inline u32 radeon_get_dstbpp(u16 depth) -{ - switch (depth) { - case 8: - return DST_8BPP; - case 15: - return DST_15BPP; - case 16: - return DST_16BPP; - case 32: - return DST_32BPP; - default: - return 0; - } -} - /* * 2D Engine helper routines */ diff --git a/drivers/video/fbsysfs.c b/drivers/video/fbsysfs.c --- a/drivers/video/fbsysfs.c +++ b/drivers/video/fbsysfs.c @@ -15,6 +15,7 @@ * are converted to use it a sysfsification will open OOPSable races. */ +#include #include #include #include @@ -190,6 +191,127 @@ static ssize_t show_modes(struct class_d return i; } +static ssize_t store_config(struct class_device *class_device, const char * buf, + size_t count) +{ + struct fb_info *fb_info = + (struct fb_info *)class_get_devdata(class_device); + int err; + char c, *y; + const char *x = buf; + unsigned int field = 0, bpp = 0; + struct fb_var_screeninfo var; + + var = fb_info->var; + while (x < buf + count) { + x++; + field = simple_strtoul(x, &y, 10); + x = y; + bpp += field; + } + if (!bpp) + return -EINVAL; + var.bits_per_pixel = bpp; + + x = buf; + while (x < buf + count) { + c = *x++; + field = simple_strtoul(x, &y, 10); + x = y; + bpp -= field; + switch (toupper(c)) { + case 'A': + var.transp.length = field; + var.transp.offset = bpp; + break; + case 'M': + var.grayscale = 1; + /* fall through */ + case 'I': + var.red.length = var.green.length = var.blue.length = field; + var.red.offset = var.green.offset = var.blue.offset = 0; + break; + case 'R': + var.red.length = field; + var.red.offset = bpp; + break; + case 'G': + var.green.length = field; + var.green.offset = bpp; + break; + case 'B': + var.blue.length = field; + var.blue.offset = bpp; + break; + } + } + if ((err = activate(fb_info, &var))) + return err; + + return count; +} + +static ssize_t show_config(struct class_device *class_device, char *buf) +{ + struct fb_info *fb_info = + (struct fb_info *)class_get_devdata(class_device); + int i, off, count; + char field[4][10]; + + count = off = 0; + buf[0] = '\n'; + + for (i = 0; i < 4; i++) { + field[i][0] = '\0'; + if ((off == 0) && ((fb_info->var.red.offset == 0) && + (fb_info->var.blue.offset == 0) && (fb_info->var.green.offset == 0))) { + snprintf(&field[i][0], sizeof(field[0]), "I%d", fb_info->var.red.length); + off += fb_info->var.red.length; + continue; + } + if ((fb_info->var.red.offset == off) && (fb_info->var.red.length != 0)) { + snprintf(&field[i][0], sizeof(field[0]), "R%d", fb_info->var.red.length); + off += fb_info->var.red.length; + continue; + } + if ((fb_info->var.green.offset == off) && (fb_info->var.green.length != 0)) { + snprintf(&field[i][0], sizeof(field[0]), "G%d", fb_info->var.green.length); + off += fb_info->var.green.length; + continue; + } + if ((fb_info->var.blue.offset == off) && (fb_info->var.blue.length != 0)) { + snprintf(&field[i][0], sizeof(field[0]), "B%d", fb_info->var.blue.length); + off += fb_info->var.blue.length; + continue; + } + if ((fb_info->var.transp.offset == off) && (fb_info->var.transp.length != 0)) { + snprintf(&field[i][0], sizeof(field[0]), "A%d", fb_info->var.transp.length); + off += fb_info->var.transp.length; + continue; + } + } + for (i = 3; i >= 0; i--) + if (field[i][0] != '\0') + count += snprintf(&buf[count], PAGE_SIZE - count, "%s", &field[i][0]); + + if (count) + count += snprintf(&buf[count], PAGE_SIZE - count, "\n"); + return count; +} + +static ssize_t show_configs(struct class_device *class_device, char *buf) +{ + struct fb_info *fb_info = + (struct fb_info *)class_get_devdata(class_device); + int count = 0; + + if (fb_info->fbops->fb_get_configs) { + strncpy(buf, fb_info->fbops->fb_get_configs(fb_info), PAGE_SIZE); + count = strlen(buf); + } + return count; +} + static ssize_t store_bpp(struct class_device *class_device, const char * buf, size_t count) { @@ -355,32 +477,6 @@ static ssize_t show_blank(struct class_d return 0; } -static ssize_t store_console(struct class_device *class_device, - const char * buf, size_t count) -{ -// struct fb_info *fb_info = (struct fb_info *)class_get_devdata(class_device); - return 0; -} - -static ssize_t show_console(struct class_device *class_device, char *buf) -{ -// struct fb_info *fb_info = (struct fb_info *)class_get_devdata(class_device); - return 0; -} - -static ssize_t store_cursor(struct class_device *class_device, - const char * buf, size_t count) -{ -// struct fb_info *fb_info = (struct fb_info *)class_get_devdata(class_device); - return 0; -} - -static ssize_t show_cursor(struct class_device *class_device, char *buf) -{ -// struct fb_info *fb_info = (struct fb_info *)class_get_devdata(class_device); - return 0; -} - static ssize_t store_pan(struct class_device *class_device, const char * buf, size_t count) { @@ -425,10 +521,10 @@ static struct class_device_attribute cla __ATTR(bits_per_pixel, S_IRUGO|S_IWUSR, show_bpp, store_bpp), __ATTR(blank, S_IRUGO|S_IWUSR, show_blank, store_blank), __ATTR(color_map, S_IRUGO|S_IWUSR, show_cmap, store_cmap), - __ATTR(console, S_IRUGO|S_IWUSR, show_console, store_console), - __ATTR(cursor, S_IRUGO|S_IWUSR, show_cursor, store_cursor), __ATTR(mode, S_IRUGO|S_IWUSR, show_mode, store_mode), __ATTR(modes, S_IRUGO|S_IWUSR, show_modes, store_modes), + __ATTR(config, S_IRUGO|S_IWUSR, show_config, store_config), + __ATTR(configs, S_IRUGO|S_IWUSR, show_configs, NULL), __ATTR(pan, S_IRUGO|S_IWUSR, show_pan, store_pan), __ATTR(virtual_size, S_IRUGO|S_IWUSR, show_virtual, store_virtual), __ATTR(name, S_IRUGO, show_name, NULL), diff --git a/include/linux/fb.h b/include/linux/fb.h --- a/include/linux/fb.h +++ b/include/linux/fb.h @@ -598,6 +598,10 @@ struct fb_ops { /* perform fb specific mmap */ int (*fb_mmap)(struct fb_info *info, struct file *file, struct vm_area_struct *vma); + + /* Get allowable configs */ + char * (*fb_get_configs) (struct fb_info *info); + }; #ifdef CONFIG_FB_TILEBLITTING diff --git a/include/video/radeon.h b/include/video/radeon.h --- a/include/video/radeon.h +++ b/include/video/radeon.h @@ -800,6 +800,18 @@ #define DST_X_LEFT_TO_RIGHT_S 0x80000000 +/* CRTC_PIC_WIDTH constants */ +#define PIX_WIDTH_I4 0x00000001 +#define PIX_WIDTH_I8 0x00000002 +#define PIX_WIDTH_A1R5G5B5 0x00000003 +#define PIX_WIDTH_R5G6B5 0x00000004 +#define PIX_WIDTH_R8B8G8 0x00000005 +#define PIX_WIDTH_A8R8G8B8 0x00000006 +#define PIX_WIDTH_A4R4B4G4 0x00000007 +#define PIX_WIDTH_A8I8 0x00000008 +#define PIX_WIDTH_A2R10G10B10 0x00000009 + + /* DP_DATATYPE bit constants */ #define DST_8BPP 0x00000002 #define DST_15BPP 0x00000003