cyber2000fb.c
来自「linux下的VIDEO接口驱动程序」· C语言 代码 · 共 1,976 行 · 第 1/4 页
C
1,976 行
static void cyber2000fb_write_ramdac_ctrl(struct cfb_info *cfb){ unsigned int i; unsigned int val = cfb->ramdac_ctrl | cfb->ramdac_powerdown; cyber2000fb_writeb(0x56, 0x3ce, cfb); i = cyber2000fb_readb(0x3cf, cfb); cyber2000fb_writeb(i | 4, 0x3cf, cfb); cyber2000fb_writeb(val, 0x3c6, cfb); cyber2000fb_writeb(i, 0x3cf, cfb);}static void cyber2000fb_set_timing(struct cfb_info *cfb, struct par_info *hw){ u_int i; /* * Blank palette */ for (i = 0; i < NR_PALETTE; i++) { cyber2000fb_writeb(i, 0x3c8, cfb); cyber2000fb_writeb(0, 0x3c9, cfb); cyber2000fb_writeb(0, 0x3c9, cfb); cyber2000fb_writeb(0, 0x3c9, cfb); } cyber2000fb_writeb(0xef, 0x3c2, cfb); cyber2000_crtcw(0x11, 0x0b, cfb); cyber2000_attrw(0x11, 0x00, cfb); cyber2000_seqw(0x00, 0x01, cfb); cyber2000_seqw(0x01, 0x01, cfb); cyber2000_seqw(0x02, 0x0f, cfb); cyber2000_seqw(0x03, 0x00, cfb); cyber2000_seqw(0x04, 0x0e, cfb); cyber2000_seqw(0x00, 0x03, cfb); for (i = 0; i < sizeof(crtc_idx); i++) cyber2000_crtcw(crtc_idx[i], hw->crtc[i], cfb); for (i = 0x0a; i < 0x10; i++) cyber2000_crtcw(i, 0, cfb); cyber2000_grphw(EXT_CRT_VRTOFL, hw->crtc_ofl, cfb); cyber2000_grphw(0x00, 0x00, cfb); cyber2000_grphw(0x01, 0x00, cfb); cyber2000_grphw(0x02, 0x00, cfb); cyber2000_grphw(0x03, 0x00, cfb); cyber2000_grphw(0x04, 0x00, cfb); cyber2000_grphw(0x05, 0x60, cfb); cyber2000_grphw(0x06, 0x05, cfb); cyber2000_grphw(0x07, 0x0f, cfb); cyber2000_grphw(0x08, 0xff, cfb); /* Attribute controller registers */ for (i = 0; i < 16; i++) cyber2000_attrw(i, i, cfb); cyber2000_attrw(0x10, 0x01, cfb); cyber2000_attrw(0x11, 0x00, cfb); cyber2000_attrw(0x12, 0x0f, cfb); cyber2000_attrw(0x13, 0x00, cfb); cyber2000_attrw(0x14, 0x00, cfb); /* PLL registers */ cyber2000_grphw(EXT_DCLK_MULT, hw->clock_mult, cfb); cyber2000_grphw(EXT_DCLK_DIV, hw->clock_div, cfb); cyber2000_grphw(EXT_MCLK_MULT, cfb->mclk_mult, cfb); cyber2000_grphw(EXT_MCLK_DIV, cfb->mclk_div, cfb); cyber2000_grphw(0x90, 0x01, cfb); cyber2000_grphw(0xb9, 0x80, cfb); cyber2000_grphw(0xb9, 0x00, cfb); cfb->ramdac_ctrl = hw->ramdac; cyber2000fb_write_ramdac_ctrl(cfb); cyber2000fb_writeb(0x20, 0x3c0, cfb); cyber2000fb_writeb(0xff, 0x3c6, cfb); cyber2000_grphw(0x14, hw->fetch, cfb); cyber2000_grphw(0x15, ((hw->fetch >> 8) & 0x03) | ((hw->pitch >> 4) & 0x30), cfb); cyber2000_grphw(EXT_SEQ_MISC, hw->extseqmisc, cfb);// cyber2000_grphw(EXT_BIU_MISC, EXT_BIU_MISC_LIN_ENABLE |// EXT_BIU_MISC_COP_ENABLE |// EXT_BIU_MISC_COP_BFC, cfb); /* * Set up accelerator registers */ cyber2000fb_writew(hw->width, CO_REG_SRC_WIDTH, cfb); cyber2000fb_writew(hw->width, CO_REG_DEST_WIDTH, cfb); cyber2000fb_writeb(hw->co_pixfmt, CO_REG_PIXFMT, cfb);}static inline intcyber2000fb_update_start(struct cfb_info *cfb, struct fb_var_screeninfo *var){ u_int base = var->yoffset * var->xres_virtual + var->xoffset; base *= var->bits_per_pixel; /* * Convert to bytes and shift two extra bits because DAC * can only start on 4 byte aligned data. */ base >>= 5; if (base >= 1 << 20) return -EINVAL; cyber2000_grphw(0x10, base >> 16 | 0x10, cfb); cyber2000_crtcw(0x0c, base >> 8, cfb); cyber2000_crtcw(0x0d, base, cfb); return 0;}/* * Set the Colormap */static intcyber2000fb_set_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info){ struct cfb_info *cfb = (struct cfb_info *)info; struct display *display = fb_display + con; struct fb_cmap *dcmap = &display->cmap; int err = 0; /* no colormap allocated? */ if (!dcmap->len) err = fb_alloc_cmap(dcmap, 256, 0); /* * we should be able to remove this test once fbcon has been * "improved" --rmk */ if (!err && display == cfb->display) { err = fb_set_cmap(cmap, kspc, cyber2000fb_setcolreg, &cfb->fb); dcmap = &cfb->fb.cmap; } if (!err) fb_copy_cmap(cmap, dcmap, kspc ? 0 : 1); return err;}static intcyber2000fb_decode_crtc(struct par_info *hw, struct cfb_info *cfb, struct fb_var_screeninfo *var){ u_int Htotal, Hblankend, Hsyncend; u_int Vtotal, Vdispend, Vblankstart, Vblankend, Vsyncstart, Vsyncend;#define BIT(v,b1,m,b2) (((v >> b1) & m) << b2) hw->crtc[13] = hw->pitch; hw->crtc[17] = 0xe3; hw->crtc[14] = 0; hw->crtc[8] = 0; Htotal = var->xres + var->right_margin + var->hsync_len + var->left_margin; if (Htotal > 2080) return -EINVAL; hw->crtc[0] = (Htotal >> 3) - 5; hw->crtc[1] = (var->xres >> 3) - 1; hw->crtc[2] = var->xres >> 3; hw->crtc[4] = (var->xres + var->right_margin) >> 3; Hblankend = (Htotal - 4*8) >> 3; hw->crtc[3] = BIT(Hblankend, 0, 0x1f, 0) | BIT(1, 0, 0x01, 7); Hsyncend = (var->xres + var->right_margin + var->hsync_len) >> 3; hw->crtc[5] = BIT(Hsyncend, 0, 0x1f, 0) | BIT(Hblankend, 5, 0x01, 7); Vdispend = var->yres - 1; Vsyncstart = var->yres + var->lower_margin; Vsyncend = var->yres + var->lower_margin + var->vsync_len; Vtotal = var->yres + var->lower_margin + var->vsync_len + var->upper_margin - 2; if (Vtotal > 2047) return -EINVAL; Vblankstart = var->yres + 6; Vblankend = Vtotal - 10; hw->crtc[6] = Vtotal; hw->crtc[7] = BIT(Vtotal, 8, 0x01, 0) | BIT(Vdispend, 8, 0x01, 1) | BIT(Vsyncstart, 8, 0x01, 2) | BIT(Vblankstart,8, 0x01, 3) | BIT(1, 0, 0x01, 4) | BIT(Vtotal, 9, 0x01, 5) | BIT(Vdispend, 9, 0x01, 6) | BIT(Vsyncstart, 9, 0x01, 7); hw->crtc[9] = BIT(0, 0, 0x1f, 0) | BIT(Vblankstart,9, 0x01, 5) | BIT(1, 0, 0x01, 6); hw->crtc[10] = Vsyncstart; hw->crtc[11] = BIT(Vsyncend, 0, 0x0f, 0) | BIT(1, 0, 0x01, 7); hw->crtc[12] = Vdispend; hw->crtc[15] = Vblankstart; hw->crtc[16] = Vblankend; hw->crtc[18] = 0xff; /* * overflow - graphics reg 0x11 * 0=VTOTAL:10 1=VDEND:10 2=VRSTART:10 3=VBSTART:10 * 4=LINECOMP:10 5-IVIDEO 6=FIXCNT */ hw->crtc_ofl = BIT(Vtotal, 10, 0x01, 0) | BIT(Vdispend, 10, 0x01, 1) | BIT(Vsyncstart, 10, 0x01, 2) | BIT(Vblankstart,10, 0x01, 3) | EXT_CRT_VRTOFL_LINECOMP10; /* woody: set the interlaced bit... */ /* FIXME: what about doublescan? */ if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) hw->crtc_ofl |= EXT_CRT_VRTOFL_INTERLACE; return 0;}/* * The following was discovered by a good monitor, bit twiddling, theorising * and but mostly luck. Strangely, it looks like everyone elses' PLL! * * Clock registers: * fclock = fpll / div2 * fpll = fref * mult / div1 * where: * fref = 14.318MHz (69842ps) * mult = reg0xb0.7:0 * div1 = (reg0xb1.5:0 + 1) * div2 = 2^(reg0xb1.7:6) * fpll should be between 115 and 260 MHz * (8696ps and 3846ps) */static intcyber2000fb_decode_clock(struct par_info *hw, struct cfb_info *cfb, struct fb_var_screeninfo *var){ u_long pll_ps = var->pixclock; const u_long ref_ps = cfb->ref_ps; u_int div2, t_div1, best_div1, best_mult; int best_diff; int vco; /* * Step 1: * find div2 such that 115MHz < fpll < 260MHz * and 0 <= div2 < 4 */ for (div2 = 0; div2 < 4; div2++) { u_long new_pll; new_pll = pll_ps / cfb->divisors[div2]; if (8696 > new_pll && new_pll > 3846) { pll_ps = new_pll; break; } } if (div2 == 4) return -EINVAL; /* * Step 2: * Given pll_ps and ref_ps, find: * pll_ps * 0.995 < pll_ps_calc < pll_ps * 1.005 * where { 1 < best_div1 < 32, 1 < best_mult < 256 } * pll_ps_calc = best_div1 / (ref_ps * best_mult) */ best_diff = 0x7fffffff; best_mult = 32; best_div1 = 255; for (t_div1 = 32; t_div1 > 1; t_div1 -= 1) { u_int rr, t_mult, t_pll_ps; int diff; /* * Find the multiplier for this divisor */ rr = ref_ps * t_div1; t_mult = (rr + pll_ps / 2) / pll_ps; /* * Is the multiplier within the correct range? */ if (t_mult > 256 || t_mult < 2) continue; /* * Calculate the actual clock period from this multiplier * and divisor, and estimate the error. */ t_pll_ps = (rr + t_mult / 2) / t_mult; diff = pll_ps - t_pll_ps; if (diff < 0) diff = -diff; if (diff < best_diff) { best_diff = diff; best_mult = t_mult; best_div1 = t_div1; } /* * If we hit an exact value, there is no point in continuing. */ if (diff == 0) break; } /* * Step 3: * combine values */ hw->clock_mult = best_mult - 1; hw->clock_div = div2 << 6 | (best_div1 - 1); vco = ref_ps * best_div1 / best_mult; if ((ref_ps == 40690) && (vco < 5556)) /* Set VFSEL when VCO > 180MHz (5.556 ps). */ hw->clock_div |= EXT_DCLK_DIV_VFSEL; return 0;}/* * Decode the info required for the hardware. * This involves the PLL parameters for the dot clock, * CRTC registers, and accelerator settings. */static intcyber2000fb_decode_var(struct fb_var_screeninfo *var, struct cfb_info *cfb, struct par_info *hw){ unsigned int mem; int err; hw->width = var->xres_virtual; hw->ramdac = RAMDAC_VREFEN | RAMDAC_DAC8BIT; var->transp.msb_right = 0; var->red.msb_right = 0; var->green.msb_right = 0; var->blue.msb_right = 0; switch (var->bits_per_pixel) {#ifdef FBCON_HAS_CFB8 case 8: /* PSEUDOCOLOUR, 256 */ hw->co_pixfmt = CO_PIXFMT_8BPP; hw->pitch = hw->width >> 3; hw->extseqmisc = EXT_SEQ_MISC_8; var->transp.offset = 0; var->transp.length = 0; var->red.offset = 0; var->red.length = 8; var->green.offset = 0; var->green.length = 8; var->blue.offset = 0; var->blue.length = 8; break;#endif#ifdef FBCON_HAS_CFB16 case 16:/* DIRECTCOLOUR, 64k or 32k */ hw->co_pixfmt = CO_PIXFMT_16BPP; hw->pitch = hw->width >> 2; switch (var->green.length) { case 6: /* RGB565, 64k */ hw->extseqmisc = EXT_SEQ_MISC_16_RGB565; var->transp.offset = 0; var->transp.length = 0; var->red.offset = 11; var->red.length = 5; var->green.offset = 5; var->green.length = 6; var->blue.offset = 0; var->blue.length = 5; break; default: case 5: /* RGB555, 32k */ hw->extseqmisc = EXT_SEQ_MISC_16_RGB555; var->transp.offset = 0; var->transp.length = 0; var->red.offset = 10; var->red.length = 5; var->green.offset = 5; var->green.length = 5; var->blue.offset = 0; var->blue.length = 5; break; case 4: /* RGB444, 4k + transparency? */ hw->extseqmisc = EXT_SEQ_MISC_16_RGB444; var->transp.offset = 12; var->transp.length = 4; var->red.offset = 8; var->red.length = 4; var->green.offset = 4; var->green.length = 4; var->blue.offset = 0; var->blue.length = 4; break; } break;#endif#ifdef FBCON_HAS_CFB24 case 24:/* TRUECOLOUR, 16m */ hw->co_pixfmt = CO_PIXFMT_24BPP; hw->width *= 3; hw->pitch = hw->width >> 3; hw->ramdac |= (RAMDAC_BYPASS | RAMDAC_RAMPWRDN); hw->extseqmisc = EXT_SEQ_MISC_24_RGB888; var->transp.offset = 0; var->transp.length = 0; var->red.offset = 16; var->red.length = 8; var->green.offset = 8; var->green.length = 8; var->blue.offset = 0; var->blue.length = 8; break;#endif#ifdef FBCON_HAS_CFB32 case 32:/* TRUECOLOUR, 16m */ hw->co_pixfmt = CO_PIXFMT_32BPP; hw->pitch = hw->width >> 1; hw->ramdac |= (RAMDAC_BYPASS | RAMDAC_RAMPWRDN); hw->extseqmisc = EXT_SEQ_MISC_32; var->transp.offset = 24; var->transp.length = 8; var->red.offset = 16; var->red.length = 8; var->green.offset = 8; var->green.length = 8; var->blue.offset = 0; var->blue.length = 8; break;#endif default: return -EINVAL; } mem = var->xres_virtual * var->yres_virtual * (var->bits_per_pixel / 8); if (mem > cfb->fb.fix.smem_len) var->yres_virtual = cfb->fb.fix.smem_len * 8 / (var->bits_per_pixel * var->xres_virtual); if (var->yres > var->yres_virtual) var->yres = var->yres_virtual; if (var->xres > var->xres_virtual) var->xres = var->xres_virtual; err = cyber2000fb_decode_clock(hw, cfb, var); if (err) return err; err = cyber2000fb_decode_crtc(hw, cfb, var); if (err) return err; hw->width -= 1; hw->fetch = hw->pitch; if (!(cfb->mem_ctl2 & MEM_CTL2_64BIT)) hw->fetch <<= 1; hw->fetch += 1; return 0;}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?