📄 cirrusfb.c
字号:
printk(KERN_ERR "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_virtual < var->xres) var->xres_virtual = var->xres; /* use highest possible virtual resolution */ if (var->yres_virtual == -1) { var->yres_virtual = pixels / var->xres_virtual; printk(KERN_INFO "cirrusfb: virtual resolution set to " "maximum of %dx%d\n", var->xres_virtual, var->yres_virtual); } if (var->yres_virtual < var->yres) var->yres_virtual = var->yres; if (var->xres_virtual * var->yres_virtual > pixels) { printk(KERN_ERR "cirrusfb: mode %dx%dx%d rejected... " "virtual resolution too high to fit into video memory!\n", var->xres_virtual, var->yres_virtual, var->bits_per_pixel); DPRINTK("EXIT - EINVAL error\n"); return -EINVAL; } 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 = var->red; var->blue = var->red; break; case 8: var->red.offset = 0; var->red.length = 6; var->green = var->red; var->blue = var->red; 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 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_ERR "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, struct fb_info *info){ long freq; long maxclock; int maxclockidx = var->bits_per_pixel >> 3; struct cirrusfb_info *cinfo = info->par; switch (var->bits_per_pixel) { case 1: info->fix.line_length = var->xres_virtual / 8; info->fix.visual = FB_VISUAL_MONO10; break; case 8: info->fix.line_length = var->xres_virtual; info->fix.visual = FB_VISUAL_PSEUDOCOLOR; break; case 16: case 32: info->fix.line_length = var->xres_virtual * maxclockidx; info->fix.visual = FB_VISUAL_TRUECOLOR; break; default: DPRINTK("Unsupported bpp size: %d\n", var->bits_per_pixel); assert(false); /* should never occur */ break; } info->fix.type = FB_TYPE_PACKED_PIXELS; /* convert from ps to kHz */ freq = PICOS2KHZ(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_ERR "cirrusfb: 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 (var->xres <= 800) /* Xbh has this type of clock for 32-bit */ freq /= 2; break; }#endif return 0;}static void cirrusfb_set_mclk_as_source(const struct cirrusfb_info *cinfo, int div){ unsigned char old1f, old1e; assert(cinfo != NULL); old1f = vga_rseq(cinfo->regbase, CL_SEQR1F) & ~0x40; if (div) { DPRINTK("Set %s as pixclock source.\n", (div == 2) ? "MCLK/2" : "MCLK"); old1f |= 0x40; old1e = vga_rseq(cinfo->regbase, CL_SEQR1E) & ~0x1; if (div == 2) old1e |= 1; vga_wseq(cinfo->regbase, CL_SEQR1E, old1e); } vga_wseq(cinfo->regbase, CL_SEQR1F, old1f);}/************************************************************************* cirrusfb_set_par_foo() actually writes the values for a new video mode into the hardware,**************************************************************************/static int cirrusfb_set_par_foo(struct fb_info *info){ struct cirrusfb_info *cinfo = info->par; struct fb_var_screeninfo *var = &info->var; struct cirrusfb_regs regs; u8 __iomem *regbase = cinfo->regbase; unsigned char tmp; int offset = 0, err; const struct cirrusfb_board_info_rec *bi; int hdispend, hsyncstart, hsyncend, htotal; int yres, vdispend, vsyncstart, vsyncend, vtotal; long freq; int nom, den, div; DPRINTK("ENTER\n"); DPRINTK("Requested mode: %dx%dx%d\n", var->xres, var->yres, var->bits_per_pixel); DPRINTK("pixclock: %d\n", var->pixclock); init_vgachip(info); err = cirrusfb_decode_var(var, ®s, info); if (err) { /* should never happen */ DPRINTK("mode change aborted. invalid var.\n"); return -EINVAL; } bi = &cirrusfb_board_info[cinfo->btype]; hsyncstart = var->xres + var->right_margin; hsyncend = hsyncstart + var->hsync_len; htotal = (hsyncend + var->left_margin) / 8 - 5; hdispend = var->xres / 8 - 1; hsyncstart = hsyncstart / 8 + 1; hsyncend = hsyncend / 8 + 1; yres = var->yres; vsyncstart = yres + var->lower_margin; vsyncend = vsyncstart + var->vsync_len; vtotal = vsyncend + var->upper_margin; vdispend = yres - 1; if (var->vmode & FB_VMODE_DOUBLE) { yres *= 2; vsyncstart *= 2; vsyncend *= 2; vtotal *= 2; } else if (var->vmode & FB_VMODE_INTERLACED) { yres = (yres + 1) / 2; vsyncstart = (vsyncstart + 1) / 2; vsyncend = (vsyncend + 1) / 2; vtotal = (vtotal + 1) / 2; } vtotal -= 2; vsyncstart -= 1; vsyncend -= 1; if (yres >= 1024) { vtotal /= 2; vsyncstart /= 2; vsyncend /= 2; vdispend /= 2; } if (regs.multiplexing) { htotal /= 2; hsyncstart /= 2; hsyncend /= 2; hdispend /= 2; } /* unlock register VGA_CRTC_H_TOTAL..CRT7 */ vga_wcrt(regbase, VGA_CRTC_V_SYNC_END, 0x20); /* previously: 0x00) */ /* if debugging is enabled, all parameters get output before writing */ DPRINTK("CRT0: %d\n", htotal); vga_wcrt(regbase, VGA_CRTC_H_TOTAL, htotal); DPRINTK("CRT1: %d\n", hdispend); vga_wcrt(regbase, VGA_CRTC_H_DISP, hdispend); DPRINTK("CRT2: %d\n", var->xres / 8); vga_wcrt(regbase, VGA_CRTC_H_BLANK_START, var->xres / 8); /* + 128: Compatible read */ DPRINTK("CRT3: 128+%d\n", (htotal + 5) % 32); vga_wcrt(regbase, VGA_CRTC_H_BLANK_END, 128 + ((htotal + 5) % 32)); DPRINTK("CRT4: %d\n", hsyncstart); vga_wcrt(regbase, VGA_CRTC_H_SYNC_START, hsyncstart); tmp = hsyncend % 32; if ((htotal + 5) & 32) tmp += 128; DPRINTK("CRT5: %d\n", tmp); vga_wcrt(regbase, VGA_CRTC_H_SYNC_END, tmp); DPRINTK("CRT6: %d\n", vtotal & 0xff); vga_wcrt(regbase, VGA_CRTC_V_TOTAL, vtotal & 0xff); tmp = 16; /* LineCompare bit #9 */ if (vtotal & 256) tmp |= 1; if (vdispend & 256) tmp |= 2; if (vsyncstart & 256) tmp |= 4; if ((vdispend + 1) & 256) tmp |= 8; if (vtotal & 512) tmp |= 32; if (vdispend & 512) tmp |= 64; if (vsyncstart & 512) tmp |= 128; DPRINTK("CRT7: %d\n", tmp); vga_wcrt(regbase, VGA_CRTC_OVERFLOW, tmp); tmp = 0x40; /* LineCompare bit #8 */ if ((vdispend + 1) & 512) tmp |= 0x20; if (var->vmode & FB_VMODE_DOUBLE) tmp |= 0x80; DPRINTK("CRT9: %d\n", tmp); vga_wcrt(regbase, VGA_CRTC_MAX_SCAN, tmp); DPRINTK("CRT10: %d\n", vsyncstart & 0xff); vga_wcrt(regbase, VGA_CRTC_V_SYNC_START, vsyncstart & 0xff); DPRINTK("CRT11: 64+32+%d\n", vsyncend % 16); vga_wcrt(regbase, VGA_CRTC_V_SYNC_END, vsyncend % 16 + 64 + 32); DPRINTK("CRT12: %d\n", vdispend & 0xff); vga_wcrt(regbase, VGA_CRTC_V_DISP_END, vdispend & 0xff); DPRINTK("CRT15: %d\n", (vdispend + 1) & 0xff); vga_wcrt(regbase, VGA_CRTC_V_BLANK_START, (vdispend + 1) & 0xff); DPRINTK("CRT16: %d\n", vtotal & 0xff); vga_wcrt(regbase, VGA_CRTC_V_BLANK_END, vtotal & 0xff); DPRINTK("CRT18: 0xff\n"); vga_wcrt(regbase, VGA_CRTC_LINE_COMPARE, 0xff); tmp = 0; if (var->vmode & FB_VMODE_INTERLACED) tmp |= 1; if ((htotal + 5) & 64) tmp |= 16; if ((htotal + 5) & 128) tmp |= 32; if (vtotal & 256) tmp |= 64; if (vtotal & 512) tmp |= 128; DPRINTK("CRT1a: %d\n", tmp); vga_wcrt(regbase, CL_CRT1A, tmp); freq = PICOS2KHZ(var->pixclock); bestclock(freq, &nom, &den, &div); /* set VCLK0 */ /* hardware RefClock: 14.31818 MHz */ /* formula: VClk = (OSC * N) / (D * (1+P)) */ /* Example: VClk = (14.31818 * 91) / (23 * (1+1)) = 28.325 MHz */ if (cinfo->btype == BT_ALPINE) { /* if freq is close to mclk or mclk/2 select mclk * as clock source */ int divMCLK = cirrusfb_check_mclk(cinfo, freq); if (divMCLK) { nom = 0; cirrusfb_set_mclk_as_source(cinfo, divMCLK); } } if (nom) { vga_wseq(regbase, CL_SEQRB, nom); tmp = den << 1; if (div != 0) tmp |= 1; /* 6 bit denom; ONLY 5434!!! (bugged me 10 days) */ if ((cinfo->btype == BT_SD64) || (cinfo->btype == BT_ALPINE) || (cinfo->btype == BT_GD5480)) tmp |= 0x80; DPRINTK("CL_SEQR1B: %ld\n", (long) tmp); vga_wseq(regbase, CL_SEQR1B, tmp); } if (yres >= 1024) /* 1280x1024 */ vga_wcrt(regbase, VGA_CRTC_MODE, 0xc7); else /* mode control: VGA_CRTC_START_HI enable, ROTATE(?), 16bit * address wrap, no compat. */ vga_wcrt(regbase, VGA_CRTC_MODE, 0xc3);/* HAEH? vga_wcrt(regbase, VGA_CRTC_V_SYNC_END, 0x20); * previously: 0x00 unlock VGA_CRTC_H_TOTAL..CRT7 */ /* don't know if it would hurt to also program this if no interlaced */ /* mode is used, but I feel better this way.. :-) */ if (var->vmode & FB_VMODE_INTERLACED) vga_wcrt(regbase, VGA_CRTC_REGS, htotal / 2); else vga_wcrt(regbase, VGA_CRTC_REGS, 0x00); /* interlace control */ vga_wseq(regbase, VGA_SEQ_CHARACTER_MAP, 0); /* adjust horizontal/vertical sync type (low/high) */ /* enable display memory & CRTC I/O address for color mode */ tmp = 0x03; if (var->sync & FB_SYNC_HOR_HIGH_ACT) tmp |= 0x40; if (var->sync & FB_SYNC_VERT_HIGH_ACT) tmp |= 0x80; WGen(cinfo, VGA_MIS_W, tmp); /* Screen A Preset Row-Scan register */ vga_wcrt(regbase, VGA_CRTC_PRESET_ROW, 0); /* text cursor on and start line */ vga_wcrt(regbase, VGA_CRTC_CURSOR_START, 0); /* text cursor end line */ vga_wcrt(regbase, VGA_CRTC_CURSOR_END, 31); /****************************************************** * * 1 bpp * */ /* programming for different color depths */ if (var->bits_per_pixel == 1) { DPRINTK("cirrusfb: preparing for 1 bit deep display\n"); vga_wgfx(regbase, VGA_GFX_MODE, 0); /* mode register */ /* SR07 */ switch (cinfo->btype) { case BT_SD64: case BT_PICCOLO: case BT_PICASSO: case BT_SPECTRUM: case BT_PICASSO4: case BT_ALPINE: case BT_GD5480: DPRINTK(" (for GD54xx)\n"); vga_wseq(regbase, CL_SEQR7, regs.multiplexing ? bi->sr07_1bpp_mux : bi->sr07_1bpp); break; case BT_LAGUNA: DPRINTK(" (for GD546x)\n"); vga_wseq(regbase, CL_SEQR7, vga_rseq(regbase, CL_SEQR7) & ~0x01); break; default: printk(KERN_WARNING "cirrusfb: unknown Board\n"); break; } /* Extended Sequencer Mode */ switch (cinfo->btype) { case BT_SD64: /* setting the SEQRF on SD64 is not necessary * (only during init) */ DPRINTK("(for SD64)\n"); /* MCLK select */ vga_wseq(regbase, CL_SEQR1F, 0x1a); break; case BT_PICCOLO: case BT_SPECTRUM: DPRINTK("(for Piccolo/Spectrum)\n"); /* ### ueberall 0x22? */ /* ##vorher 1c MCLK select */ vga_wseq(regbase, CL_SEQR1F, 0x22); /* evtl d0 bei 1 bit? avoid FIFO underruns..? */ vga_wseq(regbase, CL_SEQRF, 0xb0);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -