omap24xxfb.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,697 行 · 第 1/4 页

C
1,697
字号
	struct fb_var_screeninfo v;	u32 clkdiv, pixclock, hbp, hfp, hsw, vbp, vfp, vsw;	memcpy(&v, var, sizeof(v));	/* do board-specific checks on the var */	if (omap24xxfb_check_mode(&v))		return -EINVAL;	switch (v.bits_per_pixel) {		case 0 ... 1:			v.bits_per_pixel = 1;			break;		case 2:			v.bits_per_pixel = 2;			break;		case 3 ... 4:			v.bits_per_pixel = 4;			break;		case 5 ... 8:			v.bits_per_pixel = 8;			break;		case 9 ... 16:			if (v.grayscale)				return -EINVAL;			v.bits_per_pixel = 16;			break;		case 17 ... 32:			if (v.grayscale)				return -EINVAL;			v.bits_per_pixel = 32;			break;		default:			return -EINVAL;	}	switch (var_to_depth(&v)) {		case 1:			v.red.offset = v.green.offset = v.blue.offset = 0;			v.red.length = v.green.length = v.blue.length = 1;			v.transp.offset = v.transp.length = 0;			break;		case 2:			v.red.offset = v.green.offset = v.blue.offset = 0;			v.red.length = v.green.length = v.blue.length = 2;			v.transp.offset = v.transp.length = 0;			break;		case 4:			v.red.offset = v.green.offset = v.blue.offset = 0;			v.red.length = v.green.length = v.blue.length = 4;			v.transp.offset = v.transp.length = 0;			break;		case 8:			v.red.offset = v.green.offset = v.blue.offset = 0;			v.red.length = v.green.length = v.blue.length = 8;			v.transp.offset = v.transp.length = 0;			break;		case 12:			v.red.offset = 8;			v.green.offset = 4;			v.blue.offset = 0;			v.red.length = v.green.length = v.blue.length = 4;			v.transp.offset = v.transp.length = 0;			break;		case 16:			v.red.offset = 11;			v.green.offset = 5;			v.blue.offset = 0;			v.red.length = 5;			v.green.length = 6;			v.blue.length = 5;			v.transp.offset = v.transp.length = 0;			break;		case 24:			v.red.offset = 16;			v.green.offset = 8;			v.blue.offset = 0;			v.red.length = v.blue.length = v.green.length = 8;			v.transp.offset = v.transp.length = 0;			break;		default:			return -EINVAL;	}	/* 2048x2048 is max res supported by OMAP24xx display controller */	if (oinfo->display_xres > 2048 || oinfo->display_yres > 2048)		return -EINVAL;	if (oinfo->display_xres == 0 || oinfo->display_yres == 0)		return -EINVAL;	if (v.xres_virtual < v.xres || v.yres_virtual < v.yres)		return -EINVAL;	if (oinfo->display_xres < v.xres || oinfo->display_yres < v.yres)		return -EINVAL;	if (v.xoffset > v.xres_virtual - v.xres)		return -EINVAL;	if (v.yoffset > v.yres_virtual - v.yres)		return -EINVAL;	if ((v.bits_per_pixel < 8) && (((v.xres_virtual % 8) != 0) 		|| ((v.xres % 8) != 0) || ((v.xoffset % 8) != 0)))	{		return -EINVAL;	}	/* check if we have enough video memory to support this framebuffer */	if (((v.xres_virtual*v.yres_virtual*v.bits_per_pixel)/8) 		> info->fix.smem_len)	{		return -EINVAL;	}	/* Convert the timing parameters in the var info to the values needed 	 * to program into the display controller timing registers, and then 	 * convert the register values back to the var info values.	 */	pixclock = (v.pixclock > 0) ? v.pixclock : (oinfo->gfx_clk_period * 8);	clkdiv = pixclock / oinfo->gfx_clk_period;	if (clkdiv < 2)		/* minimum divisor is 2 */		clkdiv = 2;	else if (clkdiv > 255)		clkdiv = 255;	/* maximum divisor is 255 */	pixclock = oinfo->gfx_clk_period * clkdiv;	v.pixclock = pixclock;	/* calculate horizontal timing parameters in pixclocks */	hbp = (v.left_margin > 0) ? (v.left_margin - 1) : 0;	if (hbp > 255)		hbp = 255;	hfp = (v.right_margin > 0) ? (v.right_margin - 1) : 0;	if (hfp > 255)		hfp = 255;	hsw = (v.hsync_len > 0) ? (v.hsync_len - 1) : 0;	if (hsw > 63)		hsw = 63;	v.left_margin = hbp + 1;	v.right_margin = hfp + 1;	v.hsync_len = hsw + 1;		/* calculate vertical timing parameters in line clocks */	vbp = v.upper_margin;	if (vbp > 255)		vbp = 255;	vfp = v.lower_margin;	if (vfp > 255)		vfp = 255;	vsw = (v.vsync_len > 0) ? (v.vsync_len - 1) : v.vsync_len;	if (vsw > 63)		vsw = 63;	v.upper_margin = vbp;	v.lower_margin = vfp;	v.vsync_len = vsw + 1;	v.red.msb_right = v.green.msb_right = v.blue.msb_right 		= v.transp.msb_right = 0;	v.nonstd = 0;	v.accel_flags = 0;	memcpy(var, &v, sizeof(v));	return 0;}/* *	omap24xxfb_set_par - Alters the hardware state. *	@info: frame buffer structure that represents a single frame buffer * *	Using the fb_var_screeninfo in fb_info we set the resolution of *	this particular framebuffer. This function alters the par AND the *	fb_fix_screeninfo stored in fb_info. It does not alter var in  *	fb_info since we are using that data. This means we depend on the *	data in var inside fb_info to be supported by the hardware.  *	omap24xxfb_check_var is always called before omap24xxfb_set_par to  *	ensure this. * */static intomap24xxfb_set_par(struct fb_info *info){	struct omap24xxfb_info *oinfo = (struct omap24xxfb_info *) info->par;	struct fb_var_screeninfo *var = &info->var;	struct omap24xx_dispc_regs *dispc = &oinfo->state;	u32 gfx_format;	u32 clkdiv, pixclock, hbp, hfp, hsw, vbp, vfp, vsw;	/* update the fix screeninfo */	info->fix.line_length = (var->xres_virtual*var->bits_per_pixel)/8;	info->fix.visual = ((var_to_depth(var) <= 8) ? 				FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR);		/* Call a board-specific function to configure 	 * the display controller registers for this mode.	 * This function may modify values in dispc but must not modify 	 * values in var.	 */	omap24xxfb_change_mode(var, dispc);	/* Disable RFBI mode, which is not currently supported. */	dispc->control &= ~DISPC_CONTROL_RFBIMODE;	/* Convert the timing parameters in the var info to the values needed 	 * to program into the display controller timing registers.	 */	pixclock = (var->pixclock > 0) ? var->pixclock : 			(oinfo->gfx_clk_period * 8);	clkdiv = pixclock / oinfo->gfx_clk_period;	if (clkdiv < 2)		/* minimum divisor is 2 */		clkdiv = 2;	else if (clkdiv > 255)		clkdiv = 255;	/* maximum divisor is 255 */	dispc->divisor = (1 << DISPC_DIVISOR_LCD_SHIFT) 		       | (clkdiv << DISPC_DIVISOR_PCD_SHIFT);	/* calculate horizontal timing parameters in pixclocks */	hbp = (var->left_margin > 0) ? (var->left_margin - 1) : 0;	if (hbp > 255)		hbp = 255;	hfp = (var->right_margin > 0) ? (var->right_margin - 1) : 0;	if (hfp > 255)		hfp = 255;	hsw = (var->hsync_len > 0) ? (var->hsync_len - 1) : 0;	if (hsw > 63)		hsw = 63;	dispc->timing_h = (hbp << DISPC_TIMING_H_HBP_SHIFT) 			| (hfp << DISPC_TIMING_H_HFP_SHIFT)			| (hsw << DISPC_TIMING_H_HSW_SHIFT);		/* calculate vertical timing parameters in line clocks */	vbp = var->upper_margin;	if (vbp > 255)		vbp = 255;	vfp = var->lower_margin;	if (vfp > 255)		vfp = 255;	vsw = (var->vsync_len > 0) ? (var->vsync_len - 1) : var->vsync_len;	if (vsw > 63)		vsw = 63;	dispc->timing_v = (vbp << DISPC_TIMING_V_VBP_SHIFT) 			| (vfp << DISPC_TIMING_V_VFP_SHIFT)			| (vsw << DISPC_TIMING_V_VSW_SHIFT);	oinfo->hsync = horizontal_sync_freq(dispc, var);	oinfo->vsync = vertical_sync_freq(dispc, var);	if (oinfo->vsync > 0)		oinfo->timeout = ((HZ + oinfo->vsync - 1)/oinfo->vsync)*2;	else		oinfo->timeout = HZ/5;	/* 200ms default timeout */	/* set the sync polarity */	if (var->sync & FB_SYNC_HOR_HIGH_ACT)		dispc->pol_freq |=  DISPC_POL_FREQ_IHS;	else		dispc->pol_freq &= ~DISPC_POL_FREQ_IHS;	if (var->sync & FB_SYNC_VERT_HIGH_ACT)		dispc->pol_freq |=  DISPC_POL_FREQ_IVS;	else		dispc->pol_freq &= ~DISPC_POL_FREQ_IVS;	/* set the display size */	dispc->size_lcd = (((oinfo->display_xres - 1) 			    << DISPC_SIZE_LCD_PPL_SHIFT) & DISPC_SIZE_LCD_PPL)			| (((oinfo->display_yres - 1) 			    << DISPC_SIZE_LCD_LPP_SHIFT) & DISPC_SIZE_LCD_LPP);	dispc->size_dig = dispc->size_lcd;	/* set the graphics window size */	dispc->gfx_size = (((var->xres - 1) << DISPC_GFX_SIZE_GFXSIZEX_SHIFT) 				& DISPC_GFX_SIZE_GFXSIZEX)			| (((var->yres - 1) << DISPC_GFX_SIZE_GFXSIZEY_SHIFT)				& DISPC_GFX_SIZE_GFXSIZEY);	/* set the offset of the graphics window within the framebuffer */	dispc->gfx_ba0 = info->fix.smem_start 		+ var->yoffset*info->fix.line_length 		+ (var->xoffset*var->bits_per_pixel)/8;	dispc->gfx_ba1 = dispc->gfx_ba0;	dispc->gfx_row_inc = 1 + info->fix.line_length 		- (var->xres*var->bits_per_pixel)/8;	dispc->gfx_pixel_inc = 1;	/* Set the base address of the palette */	dispc->gfx_table_ba = oinfo->palette_phys;	/* set the graphics format */	switch(var_to_depth(var)) {		case 1:			gfx_format = DISPC_GFX_ATTRIBUTES_GFXFORMAT_BITMAP1; 			break;		case 2:			gfx_format = DISPC_GFX_ATTRIBUTES_GFXFORMAT_BITMAP2; 			break;		case 4:			gfx_format = DISPC_GFX_ATTRIBUTES_GFXFORMAT_BITMAP4; 			break;		case 8:			gfx_format = DISPC_GFX_ATTRIBUTES_GFXFORMAT_BITMAP8; 			break;		case 12:			gfx_format = DISPC_GFX_ATTRIBUTES_GFXFORMAT_RGB12; 			break;		case 16:			gfx_format = DISPC_GFX_ATTRIBUTES_GFXFORMAT_RGB16; 			break;		case 24:			gfx_format = DISPC_GFX_ATTRIBUTES_GFXFORMAT_RGB24; 			break;		default:			gfx_format = dispc->gfx_attributes 					& DISPC_GFX_ATTRIBUTES_GFXFORMAT;			break;	}	dispc->gfx_attributes &= ~DISPC_GFX_ATTRIBUTES_GFXFORMAT;	dispc->gfx_attributes |=  gfx_format;	/* disable the graphics window if its size is zero */	if (var->xres == 0 || var->yres == 0)		dispc->gfx_attributes &= ~DISPC_GFX_ATTRIBUTES_ENABLE;	else		dispc->gfx_attributes |=  DISPC_GFX_ATTRIBUTES_ENABLE;	if (!oinfo->asleep)		omap24xxfb_write_state(oinfo, dispc, oinfo->timeout);	return 0;	}/* *  	omap24xxfb_setcolreg - Sets a color register. *	@regno: Which register in the CLUT we are programming  *	@red: The red value which can be up to 16 bits wide  *	@green: The green value which can be up to 16 bits wide  *	@blue:  The blue value which can be up to 16 bits wide. *	@transp: If supported the alpha value which can be up to 16 bits wide.	 *	@info: frame buffer info structure *  *	Returns non-zero on error, or zero on success. */static intomap24xxfb_setcolreg(unsigned regno, unsigned red, unsigned green, 		     unsigned blue, unsigned transp, struct fb_info *info){	struct omap24xxfb_info *oinfo = (struct omap24xxfb_info *) info->par;	if (regno >= 256)  /* maximum number of palette entries */		return 1;	if (info->var.grayscale) {		/* grayscale = 0.30*R + 0.59*G + 0.11*B */		red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8;	}	/* Truecolor has hardware-independent 16-entry pseudo-palette */	if (info->fix.visual == FB_VISUAL_TRUECOLOR) {		u32 v;			if (regno >= 16)			return 1;		red >>= (16 - info->var.red.length);		green >>= (16 - info->var.green.length);		blue >>= (16 - info->var.blue.length);		v = (red << info->var.red.offset) |		    (green << info->var.green.offset) |		    (blue << info->var.blue.offset);		switch (info->var.bits_per_pixel) {			case 16:		   		((u16*)(info->pseudo_palette))[regno] = v;				break;			case 32:			   		((u32*)(info->pseudo_palette))[regno] = v;				break;			default:				return 1;		}		return 0;	}	red >>= 8;	green >>= 8;	blue >>= 8;	(oinfo->palette)[regno] = (red << 16) | (green << 8) | (blue << 0);	if (!oinfo->asleep) {		/* tell the display controller to reload the palette table */		dispc_reg_out(oinfo, DISPC_CONFIG, oinfo->state.config);	}	return 0;}/* *	omap24xxfb_pan_display - Pans the display. *	@var: frame buffer variable screen structure *	@info: frame buffer structure that represents a single frame buffer * *	Pan the display using the `xoffset' and `yoffset' fields of the `var'  *	structure.  We don't support wrapping and ignore the FB_VMODE_YWRAP  *	flag. * *  	If the values don't fit, return -EINVAL. * *	Returns negative errno on error, or zero on success. */static intomap24xxfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info){	struct omap24xxfb_info *oinfo = (struct omap24xxfb_info *) info->par;	struct omap24xx_dispc_regs *dispc = &oinfo->state;	u32 dispc_control;	if (var->xoffset > info->var.xres_virtual - info->var.xres)		return -EINVAL;	if (var->yoffset > info->var.yres_virtual - info->var.yres)		return -EINVAL;	if ((info->var.bits_per_pixel < 8) && ((var->xoffset % 8) != 0))	{		return -EINVAL;	}

⌨️ 快捷键说明

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