extractedLnx/linux-2.6.38/drivers/video/cirrusfb.c_cirrusfb_set_par_foo.c
static int cirrusfb_set_par_foo(struct fb_info *info)
{
struct cirrusfb_info *cinfo = info->par;
struct fb_var_screeninfo *var = &info->var;
u8 __iomem *regbase = cinfo->regbase;
unsigned char tmp;
int pitch;
const struct cirrusfb_board_info_rec *bi;
int hdispend, hsyncstart, hsyncend, htotal;
int yres, vdispend, vsyncstart, vsyncend, vtotal;
long freq;
int nom, den, div;
unsigned int control = 0, format = 0, threshold = 0;
dev_dbg(info->device, "Requested mode: %dx%dx%d\n",
var->xres, var->yres, var->bits_per_pixel);
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 24:
info->fix.line_length = var->xres_virtual *
var->bits_per_pixel >> 3;
info->fix.visual = FB_VISUAL_TRUECOLOR;
break;
}
info->fix.type = FB_TYPE_PACKED_PIXELS;
init_vgachip(info);
bi = &cirrusfb_board_info[cinfo->btype];
hsyncstart = var->xres + var->right_margin;
hsyncend = hsyncstart + var->hsync_len;
htotal = (hsyncend + var->left_margin) / 8;
hdispend = var->xres / 8;
hsyncstart = hsyncstart / 8;
hsyncend = hsyncend / 8;
vdispend = var->yres;
vsyncstart = vdispend + var->lower_margin;
vsyncend = vsyncstart + var->vsync_len;
vtotal = vsyncend + var->upper_margin;
if (var->vmode & FB_VMODE_DOUBLE) {
vdispend *= 2;
vsyncstart *= 2;
vsyncend *= 2;
vtotal *= 2;
} else if (var->vmode & FB_VMODE_INTERLACED) {
vdispend = (vdispend + 1) / 2;
vsyncstart = (vsyncstart + 1) / 2;
vsyncend = (vsyncend + 1) / 2;
vtotal = (vtotal + 1) / 2;
}
yres = vdispend;
if (yres >= 1024) {
vtotal /= 2;
vsyncstart /= 2;
vsyncend /= 2;
vdispend /= 2;
}
vdispend -= 1;
vsyncstart -= 1;
vsyncend -= 1;
vtotal -= 2;
if (cinfo->multiplexing) {
htotal /= 2;
hsyncstart /= 2;
hsyncend /= 2;
hdispend /= 2;
}
htotal -= 5;
hdispend -= 1;
hsyncstart += 1;
hsyncend += 1;
/* 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 */
dev_dbg(info->device, "CRT0: %d\n", htotal);
vga_wcrt(regbase, VGA_CRTC_H_TOTAL, htotal);
dev_dbg(info->device, "CRT1: %d\n", hdispend);
vga_wcrt(regbase, VGA_CRTC_H_DISP, hdispend);
dev_dbg(info->device, "CRT2: %d\n", var->xres / 8);
vga_wcrt(regbase, VGA_CRTC_H_BLANK_START, var->xres / 8);
/* + 128: Compatible read */
dev_dbg(info->device, "CRT3: 128+%d\n", (htotal + 5) % 32);
vga_wcrt(regbase, VGA_CRTC_H_BLANK_END,
128 + ((htotal + 5) % 32));
dev_dbg(info->device, "CRT4: %d\n", hsyncstart);
vga_wcrt(regbase, VGA_CRTC_H_SYNC_START, hsyncstart);
tmp = hsyncend % 32;
if ((htotal + 5) & 32)
tmp += 128;
dev_dbg(info->device, "CRT5: %d\n", tmp);
vga_wcrt(regbase, VGA_CRTC_H_SYNC_END, tmp);
dev_dbg(info->device, "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;
dev_dbg(info->device, "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;
dev_dbg(info->device, "CRT9: %d\n", tmp);
vga_wcrt(regbase, VGA_CRTC_MAX_SCAN, tmp);
dev_dbg(info->device, "CRT10: %d\n", vsyncstart & 0xff);
vga_wcrt(regbase, VGA_CRTC_V_SYNC_START, vsyncstart & 0xff);
dev_dbg(info->device, "CRT11: 64+32+%d\n", vsyncend % 16);
vga_wcrt(regbase, VGA_CRTC_V_SYNC_END, vsyncend % 16 + 64 + 32);
dev_dbg(info->device, "CRT12: %d\n", vdispend & 0xff);
vga_wcrt(regbase, VGA_CRTC_V_DISP_END, vdispend & 0xff);
dev_dbg(info->device, "CRT15: %d\n", (vdispend + 1) & 0xff);
vga_wcrt(regbase, VGA_CRTC_V_BLANK_START, (vdispend + 1) & 0xff);
dev_dbg(info->device, "CRT16: %d\n", vtotal & 0xff);
vga_wcrt(regbase, VGA_CRTC_V_BLANK_END, vtotal & 0xff);
dev_dbg(info->device, "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;
dev_dbg(info->device, "CRT1a: %d\n", tmp);
vga_wcrt(regbase, CL_CRT1A, tmp);
freq = PICOS2KHZ(var->pixclock);
if (var->bits_per_pixel == 24)
if (cinfo->btype == BT_ALPINE || cinfo->btype == BT_SD64)
freq *= 3;
if (cinfo->multiplexing)
freq /= 2;
if (cinfo->doubleVCLK)
freq *= 2;
bestclock(freq, &nom, &den, &div);
dev_dbg(info->device, "VCLK freq: %ld kHz nom: %d den: %d div: %d\n",
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 || cinfo->btype == BT_PICASSO4 ||
cinfo->btype == BT_SD64) {
/* if freq is close to mclk or mclk/2 select mclk
* as clock source
*/
int divMCLK = cirrusfb_check_mclk(info, freq);
if (divMCLK)
nom = 0;
cirrusfb_set_mclk_as_source(info, divMCLK);
}
if (is_laguna(cinfo)) {
long pcifc = fb_readl(cinfo->laguna_mmio + 0x3fc);
unsigned char tile = fb_readb(cinfo->laguna_mmio + 0x407);
unsigned short tile_control;
if (cinfo->btype == BT_LAGUNAB) {
tile_control = fb_readw(cinfo->laguna_mmio + 0x2c4);
tile_control &= ~0x80;
fb_writew(tile_control, cinfo->laguna_mmio + 0x2c4);
}
fb_writel(pcifc | 0x10000000l, cinfo->laguna_mmio + 0x3fc);
fb_writeb(tile & 0x3f, cinfo->laguna_mmio + 0x407);
control = fb_readw(cinfo->laguna_mmio + 0x402);
threshold = fb_readw(cinfo->laguna_mmio + 0xea);
control &= ~0x6800;
format = 0;
threshold &= 0xffc0 & 0x3fbf;
}
if (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;
/* Laguna chipset has reversed clock registers */
if (is_laguna(cinfo)) {
vga_wseq(regbase, CL_SEQRE, tmp);
vga_wseq(regbase, CL_SEQR1E, nom);
} else {
vga_wseq(regbase, CL_SEQRE, nom);
vga_wseq(regbase, CL_SEQR1E, 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);
/* 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 */
/* adjust horizontal/vertical sync type (low/high), use VCLK3 */
/* enable display memory & CRTC I/O address for color mode */
tmp = 0x03 | 0xc;
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);
/* 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) {
dev_dbg(info->device, "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:
vga_wseq(regbase, CL_SEQR7,
cinfo->multiplexing ?
bi->sr07_1bpp_mux : bi->sr07_1bpp);
break;
case BT_LAGUNA:
case BT_LAGUNAB:
vga_wseq(regbase, CL_SEQR7,
vga_rseq(regbase, CL_SEQR7) & ~0x01);
break;
default:
dev_warn(info->device, "unknown Board\n");
break;
}
/* Extended Sequencer Mode */
switch (cinfo->btype) {
case BT_PICCOLO:
case BT_SPECTRUM:
/* evtl d0 bei 1 bit? avoid FIFO underruns..? */
vga_wseq(regbase, CL_SEQRF, 0xb0);
break;
case BT_PICASSO:
/* ## vorher d0 avoid FIFO underruns..? */
vga_wseq(regbase, CL_SEQRF, 0xd0);
break;
case BT_SD64:
case BT_PICASSO4:
case BT_ALPINE:
case BT_GD5480:
case BT_LAGUNA:
case BT_LAGUNAB:
/* do nothing */
break;
default:
dev_warn(info->device, "unknown Board\n");
break;
}
/* pixel mask: pass-through for first plane */
WGen(cinfo, VGA_PEL_MSK, 0x01);
if (cinfo->multiplexing)
/* hidden dac reg: 1280x1024 */
WHDR(cinfo, 0x4a);
else
/* hidden dac: nothing */
WHDR(cinfo, 0);
/* memory mode: odd/even, ext. memory */
vga_wseq(regbase, VGA_SEQ_MEMORY_MODE, 0x06);
/* plane mask: only write to first plane */
vga_wseq(regbase, VGA_SEQ_PLANE_WRITE, 0x01);
}
/******************************************************
*
* 8 bpp
*
*/
else if (var->bits_per_pixel == 8) {
dev_dbg(info->device, "preparing for 8 bit deep display\n");
switch (cinfo->btype) {
case BT_SD64:
case BT_PICCOLO:
case BT_PICASSO:
case BT_SPECTRUM:
case BT_PICASSO4:
case BT_ALPINE:
case BT_GD5480:
vga_wseq(regbase, CL_SEQR7,
cinfo->multiplexing ?
bi->sr07_8bpp_mux : bi->sr07_8bpp);
break;
case BT_LAGUNA:
case BT_LAGUNAB:
vga_wseq(regbase, CL_SEQR7,
vga_rseq(regbase, CL_SEQR7) | 0x01);
threshold |= 0x10;
break;
default:
dev_warn(info->device, "unknown Board\n");
break;
}
switch (cinfo->btype) {
case BT_PICCOLO:
case BT_PICASSO:
case BT_SPECTRUM:
/* Fast Page-Mode writes */
vga_wseq(regbase, CL_SEQRF, 0xb0);
break;
case BT_PICASSO4:
#ifdef CONFIG_ZORRO
/* ### INCOMPLETE!! */
vga_wseq(regbase, CL_SEQRF, 0xb8);
#endif
case BT_ALPINE:
case BT_SD64:
case BT_GD5480:
case BT_LAGUNA:
case BT_LAGUNAB:
/* do nothing */
break;
default:
dev_warn(info->device, "unknown board\n");
break;
}
/* mode register: 256 color mode */
vga_wgfx(regbase, VGA_GFX_MODE, 64);
if (cinfo->multiplexing)
/* hidden dac reg: 1280x1024 */
WHDR(cinfo, 0x4a);
else
/* hidden dac: nothing */
WHDR(cinfo, 0);
}
/******************************************************
*
* 16 bpp
*
*/
else if (var->bits_per_pixel == 16) {
dev_dbg(info->device, "preparing for 16 bit deep display\n");
switch (cinfo->btype) {
case BT_PICCOLO:
case BT_SPECTRUM:
vga_wseq(regbase, CL_SEQR7, 0x87);
/* Fast Page-Mode writes */
vga_wseq(regbase, CL_SEQRF, 0xb0);
break;
case BT_PICASSO:
vga_wseq(regbase, CL_SEQR7, 0x27);
/* Fast Page-Mode writes */
vga_wseq(regbase, CL_SEQRF, 0xb0);
break;
case BT_SD64:
case BT_PICASSO4:
case BT_ALPINE:
/* Extended Sequencer Mode: 256c col. mode */
vga_wseq(regbase, CL_SEQR7,
cinfo->doubleVCLK ? 0xa3 : 0xa7);
break;
case BT_GD5480:
vga_wseq(regbase, CL_SEQR7, 0x17);
/* We already set SRF and SR1F */
break;
case BT_LAGUNA:
case BT_LAGUNAB:
vga_wseq(regbase, CL_SEQR7,
vga_rseq(regbase, CL_SEQR7) & ~0x01);
control |= 0x2000;
format |= 0x1400;
threshold |= 0x10;
break;
default:
dev_warn(info->device, "unknown Board\n");
break;
}
/* mode register: 256 color mode */
vga_wgfx(regbase, VGA_GFX_MODE, 64);
#ifdef CONFIG_PCI
WHDR(cinfo, cinfo->doubleVCLK ? 0xe1 : 0xc1);
#elif defined(CONFIG_ZORRO)
/* FIXME: CONFIG_PCI and CONFIG_ZORRO may be defined both */
WHDR(cinfo, 0xa0); /* hidden dac reg: nothing special */
#endif
}
/******************************************************
*
* 24 bpp
*
*/
else if (var->bits_per_pixel == 24) {
dev_dbg(info->device, "preparing for 24 bit deep display\n");
switch (cinfo->btype) {
case BT_PICCOLO:
case BT_SPECTRUM:
vga_wseq(regbase, CL_SEQR7, 0x85);
/* Fast Page-Mode writes */
vga_wseq(regbase, CL_SEQRF, 0xb0);
break;
case BT_PICASSO:
vga_wseq(regbase, CL_SEQR7, 0x25);
/* Fast Page-Mode writes */
vga_wseq(regbase, CL_SEQRF, 0xb0);
break;
case BT_SD64:
case BT_PICASSO4:
case BT_ALPINE:
/* Extended Sequencer Mode: 256c col. mode */
vga_wseq(regbase, CL_SEQR7, 0xa5);
break;
case BT_GD5480:
vga_wseq(regbase, CL_SEQR7, 0x15);
/* We already set SRF and SR1F */
break;
case BT_LAGUNA:
case BT_LAGUNAB:
vga_wseq(regbase, CL_SEQR7,
vga_rseq(regbase, CL_SEQR7) & ~0x01);
control |= 0x4000;
format |= 0x2400;
threshold |= 0x20;
break;
default:
dev_warn(info->device, "unknown Board\n");
break;
}
/* mode register: 256 color mode */
vga_wgfx(regbase, VGA_GFX_MODE, 64);
/* hidden dac reg: 8-8-8 mode (24 or 32) */
WHDR(cinfo, 0xc5);
}
/******************************************************
*
* unknown/unsupported bpp
*
*/
else
dev_err(info->device,
"What's this? requested color depth == %d.\n",
var->bits_per_pixel);
pitch = info->fix.line_length >> 3;
vga_wcrt(regbase, VGA_CRTC_OFFSET, pitch & 0xff);
tmp = 0x22;
if (pitch & 0x100)
tmp |= 0x10; /* offset overflow bit */
/* screen start addr #16-18, fastpagemode cycles */
vga_wcrt(regbase, CL_CRT1B, tmp);
/* screen start address bit 19 */
if (cirrusfb_board_info[cinfo->btype].scrn_start_bit19)
vga_wcrt(regbase, CL_CRT1D, (pitch >> 9) & 1);
if (is_laguna(cinfo)) {
tmp = 0;
if ((htotal + 5) & 256)
tmp |= 128;
if (hdispend & 256)
tmp |= 64;
if (hsyncstart & 256)
tmp |= 48;
if (vtotal & 1024)
tmp |= 8;
if (vdispend & 1024)
tmp |= 4;
if (vsyncstart & 1024)
tmp |= 3;
vga_wcrt(regbase, CL_CRT1E, tmp);
dev_dbg(info->device, "CRT1e: %d\n", tmp);
}
/* pixel panning */
vga_wattr(regbase, CL_AR33, 0);
/* [ EGS: SetOffset(); ] */
/* From SetOffset(): Turn on VideoEnable bit in Attribute controller */
AttrOn(cinfo);
if (is_laguna(cinfo)) {
/* no tiles */
fb_writew(control | 0x1000, cinfo->laguna_mmio + 0x402);
fb_writew(format, cinfo->laguna_mmio + 0xc0);
fb_writew(threshold, cinfo->laguna_mmio + 0xea);
}
/* finally, turn on everything - turn off "FullBandwidth" bit */
/* also, set "DotClock%2" bit where requested */
tmp = 0x01;
/*** FB_VMODE_CLOCK_HALVE in linux/fb.h not defined anymore ?
if (var->vmode & FB_VMODE_CLOCK_HALVE)
tmp |= 0x08;
*/
vga_wseq(regbase, VGA_SEQ_CLOCK_MODE, tmp);
dev_dbg(info->device, "CL_SEQR1: %d\n", tmp);
#ifdef CIRRUSFB_DEBUG
cirrusfb_dbg_reg_dump(info, NULL);
#endif
return 0;
}
Generated by GNU enscript 1.6.4.