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 + -
显示快捷键?