⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cyber2000fb.c

📁 S3C44B0X下的LCD (framebuffer)驱动资料与相关代码
💻 C
📖 第 1 页 / 共 3 页
字号:
	}	/*	 * we should be able to remove this test once fbcon has been	 * "improved" --rmk	 */	if (!err && con == cfb->currcon) {		err = fb_set_cmap(cmap, kspc, cyber2000_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) |		1 << 4;	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 |= 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){	int err;	hw->width = var->xres_virtual;	hw->palette_ctrl = 0x06;	hw->vmode = var->vmode;	switch (var->bits_per_pixel) {#ifdef FBCON_HAS_CFB8	case 8:	/* PSEUDOCOLOUR, 256 */		hw->pixformat		= PIXFORMAT_8BPP;		hw->visualid		= VISUALID_256;		hw->pitch		= hw->width >> 3;		break;#endif#ifdef FBCON_HAS_CFB16	case 16:/* DIRECTCOLOUR, 64k */#ifndef CFB16_IS_CFB15		hw->pixformat		= PIXFORMAT_16BPP;		hw->visualid		= VISUALID_64K;		hw->pitch		= hw->width >> 2;		hw->palette_ctrl	|= 0x10;		break;#endif	case 15:/* DIRECTCOLOUR, 32k */		hw->pixformat		= PIXFORMAT_16BPP;		hw->visualid		= VISUALID_32K;		hw->pitch		= hw->width >> 2;		hw->palette_ctrl	|= 0x10;		break;#endif#ifdef FBCON_HAS_CFB24	case 24:/* TRUECOLOUR, 16m */		hw->pixformat		= PIXFORMAT_24BPP;		hw->visualid		= VISUALID_16M;		hw->width		*= 3;		hw->pitch		= hw->width >> 3;		hw->palette_ctrl	|= 0x10;		break;#endif#ifdef FBCON_HAS_CFB32	case 32:/* TRUECOLOUR, 16m */		hw->pixformat		= PIXFORMAT_32BPP;		hw->visualid		= VISUALID_16M_32;		hw->pitch		= hw->width >> 1;		hw->palette_ctrl	|= 0x10;		break;#endif	default:		return -EINVAL;	}	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;}/* *    Set the User Defined Part of the Display */static intcyber2000fb_set_var(struct fb_var_screeninfo *var, int con,		    struct fb_info *info){	struct cfb_info *cfb = (struct cfb_info *)info;	struct display *display;	struct par_info hw;	int err, chgvar = 0;	/*	 * CONUPDATE and SMOOTH_XPAN are equal.  However,	 * SMOOTH_XPAN is only used internally by fbcon.	 */	if (var->vmode & FB_VMODE_CONUPDATE) {		var->vmode |= FB_VMODE_YWRAP;		var->xoffset = cfb->fb.var.xoffset;		var->yoffset = cfb->fb.var.yoffset;	}	err = cyber2000fb_decode_var(var, (struct cfb_info *)info, &hw);	if (err)		return err;	if (var->activate & FB_ACTIVATE_TEST)		return 0;	if ((var->activate & FB_ACTIVATE_MASK) != FB_ACTIVATE_NOW)		return -EINVAL;	if (cfb->fb.var.xres != var->xres)		chgvar = 1;	if (cfb->fb.var.yres != var->yres)		chgvar = 1;	if (cfb->fb.var.xres_virtual != var->xres_virtual)		chgvar = 1;	if (cfb->fb.var.yres_virtual != var->yres_virtual)		chgvar = 1;	if (cfb->fb.var.bits_per_pixel != var->bits_per_pixel)		chgvar = 1;	if (con < 0) {		display = cfb->fb.disp;		chgvar = 0;	} else {		display = fb_display + con;	}	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 */		var->red.offset		= 0;		var->red.length		= 8;		var->green.offset	= 0;		var->green.length	= 8;		var->blue.offset	= 0;		var->blue.length	= 8;		cfb->fb.fix.visual	= FB_VISUAL_PSEUDOCOLOR;		cfb->dispsw		= &fbcon_cfb8;		display->dispsw_data	= NULL;		display->next_line	= var->xres_virtual;		break;#endif#ifdef FBCON_HAS_CFB16	case 16:/* DIRECTCOLOUR, 64k */#ifndef CFB16_IS_CFB15		var->red.offset		= 11;		var->red.length		= 5;		var->green.offset	= 5;		var->green.length	= 6;		var->blue.offset	= 0;		var->blue.length	= 5;		cfb->fb.fix.visual	= FB_VISUAL_DIRECTCOLOR;		cfb->dispsw		= &fbcon_cfb16;		display->dispsw_data	= cfb->fb.pseudo_palette;		display->next_line	= var->xres_virtual * 2;		break;#endif	case 15:/* DIRECTCOLOUR, 32k */		var->bits_per_pixel	= 15;		var->red.offset		= 10;		var->red.length		= 5;		var->green.offset	= 5;		var->green.length	= 5;		var->blue.offset	= 0;		var->blue.length	= 5;		cfb->fb.fix.visual	= FB_VISUAL_DIRECTCOLOR;		cfb->dispsw		= &fbcon_cfb16;		display->dispsw_data	= cfb->fb.pseudo_palette;		display->next_line	= var->xres_virtual * 2;		break;#endif#ifdef FBCON_HAS_CFB24	case 24:/* TRUECOLOUR, 16m */		var->red.offset		= 16;		var->red.length		= 8;		var->green.offset	= 8;		var->green.length	= 8;		var->blue.offset	= 0;		var->blue.length	= 8;		cfb->fb.fix.visual	= FB_VISUAL_TRUECOLOR;		cfb->dispsw		= &fbcon_cfb24;		display->dispsw_data	= cfb->fb.pseudo_palette;		display->next_line	= var->xres_virtual * 3;		break;#endif#ifdef FBCON_HAS_CFB32	case 32:/* TRUECOLOUR, 16m */		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;		cfb->fb.fix.visual	= FB_VISUAL_TRUECOLOR;		cfb->dispsw		= &fbcon_cfb32;		display->dispsw_data	= cfb->fb.pseudo_palette;		display->next_line	= var->xres_virtual * 4;		break;#endif	default:/* in theory this should never happen */		printk(KERN_WARNING "%s: no support for %dbpp\n",		       cfb->fb.fix.id, var->bits_per_pixel);		cfb->dispsw = &fbcon_dummy;		break;	}	if (var->accel_flags & FB_ACCELF_TEXT && cfb->dispsw != &fbcon_dummy)		display->dispsw = &fbcon_cyber_accel;	else		display->dispsw = cfb->dispsw;	cfb->fb.fix.line_length	= display->next_line;	display->screen_base	= cfb->fb.screen_base;	display->line_length	= cfb->fb.fix.line_length;	display->visual		= cfb->fb.fix.visual;	display->type		= cfb->fb.fix.type;	display->type_aux	= cfb->fb.fix.type_aux;	display->ypanstep	= cfb->fb.fix.ypanstep;	display->ywrapstep	= cfb->fb.fix.ywrapstep;	display->can_soft_blank = 1;	display->inverse	= 0;	cfb->fb.var = *var;	cfb->fb.var.activate &= ~FB_ACTIVATE_ALL;	/*	 * Update the old var.  The fbcon drivers still use this.	 * Once they are using cfb->fb.var, this can be dropped.	 *					--rmk	 */	display->var = cfb->fb.var;	/*	 * If we are setting all the virtual consoles, also set the	 * defaults used to create new consoles.	 */	if (var->activate & FB_ACTIVATE_ALL)		cfb->fb.disp->var = cfb->fb.var;	if (chgvar && info && cfb->fb.changevar)		cfb->fb.changevar(con);	cyber2000fb_update_start(cfb, var);	cyber2000fb_set_timing(cfb, &hw);	fb_set_cmap(&cfb->fb.cmap, 1, cyber2000_setcolreg, &cfb->fb);	return 0;}/* *    Pan or Wrap the Display */static intcyber2000fb_pan_display(struct fb_var_screeninfo *var, int con,			struct fb_info *info){	struct cfb_info *cfb = (struct cfb_info *)info;	u_int y_bottom;	y_bottom = var->yoffset;	if (!(var->vmode & FB_VMODE_YWRAP))		y_bottom += var->yres;	if (var->xoffset > (var->xres_virtual - var->xres))		return -EINVAL;	if (y_bottom > cfb->fb.var.yres_virtual)		return -EINVAL;	if (cyber2000fb_update_start(cfb, var))		return -EINVAL;	cfb->fb.var.xoffset = var->xoffset;	cfb->fb.var.yoffset = var->yoffset;	if (var->vmode & FB_VMODE_YWRAP) {		cfb->fb.var.vmode |= FB_VMODE_YWRAP;	} else {		cfb->fb.var.vmode &= ~FB_VMODE_YWRAP;	}	return 0;}/* *    Update the `var' structure (called by fbcon.c) * *    This call looks only at yoffset and the FB_VMODE_YWRAP flag in `var'. *    Since it's called by a kernel driver, no range checking is done. */static int cyber2000fb_updatevar(int con, struct fb_info *info){	struct cfb_info *cfb = (struct cfb_info *)info;	return cyber2000fb_update_start(cfb, &fb_display[con].var);}static int cyber2000fb_switch(int con, struct fb_info *info){	struct cfb_info *cfb = (struct cfb_info *)info;	struct display *disp;	struct fb_cmap *cmap;	if (cfb->currcon >= 0) {		disp = fb_display + cfb->currcon;		/*		 * Save the old colormap and video mode.		 */		disp->var = cfb->fb.var;		if (disp->cmap.len)			fb_copy_cmap(&cfb->fb.cmap, &disp->cmap, 0);	}	cfb->currcon = con;	disp = fb_display + con;	/*	 * Install the new colormap and change the video mode.  By default,	 * fbcon sets all the colormaps and video modes to the default	 * values at bootup.	 *	 * Really, we want to set the colourmap size depending on the	 * depth of the new video mode.  For now, we leave it at its	 * default 256 entry.	 */	if (disp->cmap.len)		cmap = &disp->cmap;	else		cmap = fb_default_cmap(1 << disp->var.bits_per_pixel);	fb_copy_cmap(cmap, &cfb->fb.cmap, 0);	cfb->fb.var = disp->var;	cfb->fb.var.activate = FB_ACTIVATE_NOW;	cyber2000fb_set_var(&cfb->fb.var, con, &cfb->fb);	return 0;}/* *    (Un)Blank the display. */static void cyber2000fb_blank(int blank, struct fb_info *info){	struct cfb_info *cfb = (struct cfb_info *)info;	int i;	/*	 *  Blank the screen if blank_mode != 0, else unblank. If	 *  blank == NULL then the caller blanks by setting the CLUT	 *  (Color Look Up Table) to all black. Return 0 if blanking	 *  succeeded, != 0 if un-/blanking failed due to e.g. a	 *  video mode which doesn't support it. Implements VESA	 *  suspend and powerdown modes on hardware that supports	 *  disabling hsync/vsync:	 *    blank_mode == 2: suspend vsync	 *    blank_mode == 3: suspend hsync	 *    blank_mode == 4: powerdown	 *	 *  wms...Enable VESA DMPS compatible powerdown mode	 *  run "setterm -powersave powerdown" to take advantage	 */     	switch (blank) {	case 4:	/* powerdown - both sync lines down */    		cyber2000_grphw(0x16, 0x05, cfb);		break;		case 3:	/* hsync off */    		cyber2000_grphw(0x16, 0x01, cfb);		break;		case 2:	/* vsync off */    		cyber2000_grphw(0x16, 0x04, cfb);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -