cirrusfb.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,329 行 · 第 1/5 页
C
2,329 行
.red = { .length = 8 }, .green = { .length = 8 }, .blue = { .length = 8 }, .width = -1, .height = -1, .pixclock = 20000, .left_margin = 128, .right_margin = 16, .upper_margin = 24, .lower_margin = 2, .hsync_len = 96, .vsync_len = 6, .vmode = FB_VMODE_NONINTERLACED } }, { /* * Modeline from XF86Config: * Mode "1024x768" 80 1024 1136 1340 1432 768 770 774 805 */ /* 1024x768, 55.8 kHz, 70 Hz, 80 MHz PixClock */ .name = "1024x768", .var = { .xres = 1024, .yres = 768, .xres_virtual = 1024, .yres_virtual = 768, .bits_per_pixel = 8, .red = { .length = 8 }, .green = { .length = 8 }, .blue = { .length = 8 }, .width = -1, .height = -1, .pixclock = 12500, .left_margin = 144, .right_margin = 32, .upper_margin = 30, .lower_margin = 2, .hsync_len = 192, .vsync_len = 6, .vmode = FB_VMODE_NONINTERLACED } }};#define NUM_TOTAL_MODES ARRAY_SIZE(cirrusfb_predefined)/****************************************************************************//**** BEGIN PROTOTYPES ******************************************************//*--- Interface used by the world ------------------------------------------*/int cirrusfb_init (void);int cirrusfb_setup (char *options);int cirrusfb_open (struct fb_info *info, int user);int cirrusfb_release (struct fb_info *info, int user);int cirrusfb_setcolreg (unsigned regno, unsigned red, unsigned green, unsigned blue, unsigned transp, struct fb_info *info);int cirrusfb_check_var (struct fb_var_screeninfo *var, struct fb_info *info);int cirrusfb_set_par (struct fb_info *info);int cirrusfb_pan_display (struct fb_var_screeninfo *var, struct fb_info *info);int cirrusfb_blank (int blank_mode, struct fb_info *info);void cirrusfb_fillrect (struct fb_info *info, const struct fb_fillrect *region);void cirrusfb_copyarea(struct fb_info *info, const struct fb_copyarea *area);void cirrusfb_imageblit(struct fb_info *info, const struct fb_image *image);/* function table of the above functions */static struct fb_ops cirrusfb_ops = { .owner = THIS_MODULE, .fb_open = cirrusfb_open, .fb_release = cirrusfb_release, .fb_setcolreg = cirrusfb_setcolreg, .fb_check_var = cirrusfb_check_var, .fb_set_par = cirrusfb_set_par, .fb_pan_display = cirrusfb_pan_display, .fb_blank = cirrusfb_blank, .fb_fillrect = cirrusfb_fillrect, .fb_copyarea = cirrusfb_copyarea, .fb_imageblit = cirrusfb_imageblit, .fb_cursor = soft_cursor,};/*--- Hardware Specific Routines -------------------------------------------*/static int cirrusfb_decode_var (const struct fb_var_screeninfo *var, struct cirrusfb_regs *regs, const struct fb_info *info);/*--- Internal routines ----------------------------------------------------*/static void init_vgachip (struct cirrusfb_info *cinfo);static void switch_monitor (struct cirrusfb_info *cinfo, int on);static void WGen (const struct cirrusfb_info *cinfo, int regnum, unsigned char val);static unsigned char RGen (const struct cirrusfb_info *cinfo, int regnum);static void AttrOn (const struct cirrusfb_info *cinfo);static void WHDR (const struct cirrusfb_info *cinfo, unsigned char val);static void WSFR (struct cirrusfb_info *cinfo, unsigned char val);static void WSFR2 (struct cirrusfb_info *cinfo, unsigned char val);static void WClut (struct cirrusfb_info *cinfo, unsigned char regnum, unsigned char red, unsigned char green, unsigned char blue);#if 0static void RClut (struct cirrusfb_info *cinfo, unsigned char regnum, unsigned char *red, unsigned char *green, unsigned char *blue);#endifstatic void cirrusfb_WaitBLT (caddr_t regbase);static void cirrusfb_BitBLT (caddr_t regbase, int bits_per_pixel, u_short curx, u_short cury, u_short destx, u_short desty, u_short width, u_short height, u_short line_length);static void cirrusfb_RectFill (caddr_t regbase, int bits_per_pixel, u_short x, u_short y, u_short width, u_short height, u_char color, u_short line_length);static void bestclock (long freq, long *best, long *nom, long *den, long *div, long maxfreq);#ifdef CIRRUSFB_DEBUGstatic void cirrusfb_dump (void);static void cirrusfb_dbg_reg_dump (caddr_t regbase);static void cirrusfb_dbg_print_regs (caddr_t regbase, cirrusfb_dbg_reg_class_t reg_class,...);static void cirrusfb_dbg_print_byte (const char *name, unsigned char val);#endif /* CIRRUSFB_DEBUG *//*** END PROTOTYPES ********************************************************//*****************************************************************************//*** BEGIN Interface Used by the World ***************************************/static int opencount = 0;/*--- Open /dev/fbx ---------------------------------------------------------*/int cirrusfb_open (struct fb_info *info, int user){ if (opencount++ == 0) switch_monitor (info->par, 1); return 0;}/*--- Close /dev/fbx --------------------------------------------------------*/int cirrusfb_release (struct fb_info *info, int user){ if (--opencount == 0) switch_monitor (info->par, 0); return 0;}/**** END Interface used by the World *************************************//****************************************************************************//**** BEGIN Hardware specific Routines **************************************//* Get a good MCLK value */static long cirrusfb_get_mclk (long freq, int bpp, long *div){ long mclk; assert (div != NULL); /* Calculate MCLK, in case VCLK is high enough to require > 50MHz. * Assume a 64-bit data path for now. The formula is: * ((B * PCLK * 2)/W) * 1.2 * B = bytes per pixel, PCLK = pixclock, W = data width in bytes */ mclk = ((bpp / 8) * freq * 2) / 4; mclk = (mclk * 12) / 10; if (mclk < 50000) mclk = 50000; DPRINTK ("Use MCLK of %ld kHz\n", mclk); /* Calculate value for SR1F. Multiply by 2 so we can round up. */ mclk = ((mclk * 16) / 14318); mclk = (mclk + 1) / 2; DPRINTK ("Set SR1F[5:0] to 0x%lx\n", mclk); /* Determine if we should use MCLK instead of VCLK, and if so, what we * should divide it by to get VCLK */ switch (freq) { case 24751 ... 25249: *div = 2; DPRINTK ("Using VCLK = MCLK/2\n"); break; case 49501 ... 50499: *div = 1; DPRINTK ("Using VCLK = MCLK\n"); break; default: *div = 0; break; } return mclk;}int cirrusfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info){ struct cirrusfb_info *cinfo = info->par; int nom, den; /* translyting from pixels->bytes */ int yres, i; static struct { int xres, yres; } modes[] = { { 1600, 1280 }, { 1280, 1024 }, { 1024, 768 }, { 800, 600 }, { 640, 480 }, { -1, -1 } }; switch (var->bits_per_pixel) { case 0 ... 1: var->bits_per_pixel = 1; nom = 4; den = 8; break; /* 8 pixel per byte, only 1/4th of mem usable */ case 2 ... 8: var->bits_per_pixel = 8; nom = 1; den = 1; break; /* 1 pixel == 1 byte */ case 9 ... 16: var->bits_per_pixel = 16; nom = 2; den = 1; break; /* 2 bytes per pixel */ case 17 ... 24: var->bits_per_pixel = 24; nom = 3; den = 1; break; /* 3 bytes per pixel */ case 25 ... 32: var->bits_per_pixel = 32; nom = 4; den = 1; break; /* 4 bytes per pixel */ default: printk ("cirrusfb: mode %dx%dx%d rejected...color depth not supported.\n", var->xres, var->yres, var->bits_per_pixel); DPRINTK ("EXIT - EINVAL error\n"); return -EINVAL; } if (var->xres * nom / den * var->yres > cinfo->size) { printk ("cirrusfb: mode %dx%dx%d rejected...resolution too high to fit into video memory!\n", var->xres, var->yres, var->bits_per_pixel); DPRINTK ("EXIT - EINVAL error\n"); return -EINVAL; } /* use highest possible virtual resolution */ if (var->xres_virtual == -1 && var->yres_virtual == -1) { printk ("cirrusfb: using maximum available virtual resolution\n"); for (i = 0; modes[i].xres != -1; i++) { if (modes[i].xres * nom / den * modes[i].yres < cinfo->size / 2) break; } if (modes[i].xres == -1) { printk ("cirrusfb: could not find a virtual resolution that fits into video memory!!\n"); DPRINTK ("EXIT - EINVAL error\n"); return -EINVAL; } var->xres_virtual = modes[i].xres; var->yres_virtual = modes[i].yres; printk ("cirrusfb: virtual resolution set to maximum of %dx%d\n", var->xres_virtual, var->yres_virtual); } if (var->xres_virtual < var->xres) var->xres_virtual = var->xres; if (var->yres_virtual < var->yres) var->yres_virtual = var->yres; if (var->xoffset < 0) var->xoffset = 0; if (var->yoffset < 0) var->yoffset = 0; /* truncate xoffset and yoffset to maximum if too high */ if (var->xoffset > var->xres_virtual - var->xres) var->xoffset = var->xres_virtual - var->xres - 1; if (var->yoffset > var->yres_virtual - var->yres) var->yoffset = var->yres_virtual - var->yres - 1; switch (var->bits_per_pixel) { case 1: var->red.offset = 0; var->red.length = 1; var->green.offset = 0; var->green.length = 1; var->blue.offset = 0; var->blue.length = 1; break; case 8: var->red.offset = 0; var->red.length = 6; var->green.offset = 0; var->green.length = 6; var->blue.offset = 0; var->blue.length = 6; break; case 16: if(isPReP) { var->red.offset = 2; var->green.offset = -3; var->blue.offset = 8; } else { var->red.offset = 10; var->green.offset = 5; var->blue.offset = 0; } var->red.length = 5; var->green.length = 5; var->blue.length = 5; break; case 24: if(isPReP) { var->red.offset = 8; var->green.offset = 16; var->blue.offset = 24; } else { var->red.offset = 16; var->green.offset = 8; var->blue.offset = 0; } var->red.length = 8; var->green.length = 8; var->blue.length = 8; break; case 32: if(isPReP) { var->red.offset = 8; var->green.offset = 16; var->blue.offset = 24; } else { var->red.offset = 16; var->green.offset = 8; var->blue.offset = 0; } var->red.length = 8; var->green.length = 8; var->blue.length = 8; break; default: DPRINTK("Unsupported bpp size: %d\n", var->bits_per_pixel); assert (FALSE); /* should never occur */ break; } var->red.msb_right = var->green.msb_right = var->blue.msb_right = var->transp.offset = var->transp.length = var->transp.msb_right = 0; yres = var->yres; if (var->vmode & FB_VMODE_DOUBLE) yres *= 2; else if (var->vmode & FB_VMODE_INTERLACED) yres = (yres + 1) / 2; if (yres >= 1280) { printk (KERN_WARNING "cirrusfb: ERROR: VerticalTotal >= 1280; special treatment required! (TODO)\n"); DPRINTK ("EXIT - EINVAL error\n"); return -EINVAL; } return 0;}static int cirrusfb_decode_var (const struct fb_var_screeninfo *var, struct cirrusfb_regs *regs, const struct fb_info *info){ long freq; long maxclock; int maxclockidx = 0; struct cirrusfb_info *cinfo = info->par; int xres, hfront, hsync, hback; int yres, vfront, vsync, vback; switch(var->bits_per_pixel) { case 1: regs->line_length = var->xres_virtual / 8; regs->visual = FB_VISUAL_MONO10; maxclockidx = 0; break; case 8: regs->line_length = var->xres_virtual; regs->visual = FB_VISUAL_PSEUDOCOLOR; maxclockidx = 1; break; case 16: regs->line_length = var->xres_virtual * 2; regs->visual = FB_VISUAL_DIRECTCOLOR; maxclockidx = 2; break; case 24: regs->line_length = var->xres_virtual * 3; regs->visual = FB_VISUAL_DIRECTCOLOR; maxclockidx = 3; break; case 32: regs->line_length = var->xres_virtual * 4; regs->visual = FB_VISUAL_DIRECTCOLOR; maxclockidx = 4; break; default: DPRINTK("Unsupported bpp size: %d\n", var->bits_per_pixel); assert (FALSE); /* should never occur */ break; } regs->type = FB_TYPE_PACKED_PIXELS; /* convert from ps to kHz */ freq = 1000000000 / var->pixclock; DPRINTK ("desired pixclock: %ld kHz\n", freq); maxclock = cirrusfb_board_info[cinfo->btype].maxclock[maxclockidx]; regs->multiplexing = 0; /* If the frequency is greater than we can support, we might be able * to use multiplexing for the video mode */ if (freq > maxclock) { switch (cinfo->btype) { case BT_ALPINE: case BT_GD5480: regs->multiplexing = 1; break; default: printk (KERN_WARNING "cirrusfb: ERROR: Frequency greater than maxclock (%ld kHz)\n", maxclock); DPRINTK ("EXIT - return -EINVAL\n"); return -EINVAL; } }#if 0 /* TODO: If we have a 1MB 5434, we need to put ourselves in a mode where * the VCLK is double the pixel clock. */ switch (var->bits_per_pixel) { case 16: case 32: if (regs->HorizRes <= 800) freq /= 2; /* Xbh has this type of clock for 32-bit */ break; }#endif bestclock (freq, ®s->freq, ®s->nom, ®s->den, ®s->div,
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?