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

📄 acornfb.c

📁 S3C44B0X下的LCD (framebuffer)驱动资料与相关代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* *  linux/drivers/video/acornfb.c * *  Copyright (C) 1998-2001 Russell King * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Frame buffer code for Acorn platforms * * NOTE: Most of the modes with X!=640 will disappear shortly. * NOTE: Startup setting of HS & VS polarity not supported. *       (do we need to support it if we're coming up in 640x480?) */#include <linux/config.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/errno.h>#include <linux/string.h>#include <linux/ctype.h>#include <linux/mm.h>#include <linux/tty.h>#include <linux/slab.h>#include <linux/init.h>#include <linux/fb.h>#include <asm/hardware.h>#include <asm/io.h>#include <asm/irq.h>#include <asm/mach-types.h>#include <asm/uaccess.h>#include <video/fbcon.h>#include <video/fbcon-mfb.h>#include <video/fbcon-cfb2.h>#include <video/fbcon-cfb4.h>#include <video/fbcon-cfb8.h>#include <video/fbcon-cfb16.h>#include <video/fbcon-cfb32.h>#include "acornfb.h"/* * VIDC machines can't do 16 or 32BPP modes. */#ifdef HAS_VIDC#undef FBCON_HAS_CFB16#undef FBCON_HAS_CFB32#endif/* * Default resolution. * NOTE that it has to be supported in the table towards * the end of this file. */#define DEFAULT_XRES	640#define DEFAULT_YRES	480/* * The order here defines which BPP we * pick depending on which resolutions * we have configured. */#if   defined(FBCON_HAS_CFB4)# define DEFAULT_BPP	4#elif defined(FBCON_HAS_CFB8)# define DEFAULT_BPP	8#elif defined(FBCON_HAS_CFB16)# define DEFAULT_BPP	16#elif defined(FBCON_HAS_CFB2)# define DEFAULT_BPP	2#elif defined(FBCON_HAS_MFB)# define DEFAULT_BPP	1#else#error No suitable framebuffers configured#endif/* * define this to debug the video mode selection */#undef DEBUG_MODE_SELECTION/* * Translation from RISC OS monitor types to actual * HSYNC and VSYNC frequency ranges.  These are * probably not right, but they're the best info I * have.  Allow 1% either way on the nominal for TVs. */#define NR_MONTYPES	6static struct fb_monspecs monspecs[NR_MONTYPES] __initdata = {	{ 15469, 15781, 49, 51, 0 },	/* TV		*/	{     0, 99999,  0, 99, 0 },	/* Multi Freq	*/	{ 58608, 58608, 64, 64, 0 },	/* Hi-res mono	*/	{ 30000, 70000, 60, 60, 0 },	/* VGA		*/	{ 30000, 70000, 56, 75, 0 },	/* SVGA		*/	{ 30000, 70000, 60, 60, 0 }};static struct display global_disp;static struct fb_info fb_info;static struct acornfb_par current_par;static struct vidc_timing current_vidc;static struct fb_var_screeninfo __initdata init_var = {};extern int acornfb_depth;	/* set by setup.c */extern unsigned int vram_size;	/* set by setup.c */#ifdef HAS_VIDC#define MAX_SIZE	480*1024/* CTL     VIDC	Actual * 24.000  0	 8.000 * 25.175  0	 8.392 * 36.000  0	12.000 * 24.000  1	12.000 * 25.175  1	12.588 * 24.000  2	16.000 * 25.175  2	16.783 * 36.000  1	18.000 * 24.000  3	24.000 * 36.000  2	24.000 * 25.175  3	25.175 * 36.000  3	36.000 */struct pixclock {	u_long	min_clock;	u_long	max_clock;	u_int	vidc_ctl;	u_int	vid_ctl;};static struct pixclock arc_clocks[] = {	/* we allow +/-1% on these */	{ 123750, 126250, VIDC_CTRL_DIV3,   VID_CTL_24MHz },	/*  8.000MHz */	{  82500,  84167, VIDC_CTRL_DIV2,   VID_CTL_24MHz },	/* 12.000MHz */	{  61875,  63125, VIDC_CTRL_DIV1_5, VID_CTL_24MHz },	/* 16.000MHz */	{  41250,  42083, VIDC_CTRL_DIV1,   VID_CTL_24MHz },	/* 24.000MHz */};#ifdef CONFIG_ARCH_A5Kstatic struct pixclock a5k_clocks[] = {	{ 117974, 120357, VIDC_CTRL_DIV3,   VID_CTL_25MHz },	/*  8.392MHz */	{  78649,  80238, VIDC_CTRL_DIV2,   VID_CTL_25MHz },	/* 12.588MHz */	{  58987,  60178, VIDC_CTRL_DIV1_5, VID_CTL_25MHz },	/* 16.588MHz */	{  55000,  56111, VIDC_CTRL_DIV2,   VID_CTL_36MHz },	/* 18.000MHz */	{  39325,  40119, VIDC_CTRL_DIV1,   VID_CTL_25MHz },	/* 25.175MHz */	{  27500,  28055, VIDC_CTRL_DIV1,   VID_CTL_36MHz },	/* 36.000MHz */};#endifstatic struct pixclock *acornfb_valid_pixrate(u_long pixclock){	u_int i;	for (i = 0; i < ARRAY_SIZE(arc_clocks); i++)		if (pixclock > arc_clocks[i].min_clock &&		    pixclock < arc_clocks[i].max_clock)			return arc_clocks + i;#ifdef CONFIG_ARCH_A5K	if (machine_is_a5k()) {		for (i = 0; i < ARRAY_SIZE(a5k_clocks); i++)			if (pixclock > a5k_clocks[i].min_clock &&			    pixclock < a5k_clocks[i].max_clock)				return a5k_clocks + i;	}#endif	return NULL;}/* VIDC Rules: * hcr  : must be even (interlace, hcr/2 must be even) * hswr : must be even * hdsr : must be odd * hder : must be odd * * vcr  : must be odd * vswr : >= 1 * vdsr : >= 1 * vder : >= vdsr * if interlaced, then hcr/2 must be even */static voidacornfb_set_timing(struct fb_var_screeninfo *var){	struct pixclock *pclk;	struct vidc_timing vidc;	u_int horiz_correction;	u_int sync_len, display_start, display_end, cycle;	u_int is_interlaced;	u_int vid_ctl, vidc_ctl;	u_int bandwidth;	memset(&vidc, 0, sizeof(vidc));	pclk = acornfb_valid_pixrate(var->pixclock);	vidc_ctl = pclk->vidc_ctl;	vid_ctl  = pclk->vid_ctl;	bandwidth = var->pixclock * 8 / var->bits_per_pixel;	/* 25.175, 4bpp = 79.444ns per byte, 317.776ns per word: fifo = 2,6 */	if (bandwidth > 143500)		vidc_ctl |= VIDC_CTRL_FIFO_3_7;	else if (bandwidth > 71750)		vidc_ctl |= VIDC_CTRL_FIFO_2_6;	else if (bandwidth > 35875)		vidc_ctl |= VIDC_CTRL_FIFO_1_5;	else		vidc_ctl |= VIDC_CTRL_FIFO_0_4;	switch (var->bits_per_pixel) {	case 1:		horiz_correction = 19;		vidc_ctl |= VIDC_CTRL_1BPP;		break;	case 2:		horiz_correction = 11;		vidc_ctl |= VIDC_CTRL_2BPP;		break;	case 4:		horiz_correction = 7;		vidc_ctl |= VIDC_CTRL_4BPP;		break;	default:	case 8:		horiz_correction = 5;		vidc_ctl |= VIDC_CTRL_8BPP;		break;	}	if (var->sync & FB_SYNC_COMP_HIGH_ACT) /* should be FB_SYNC_COMP */		vidc_ctl |= VIDC_CTRL_CSYNC;	else {		if (!(var->sync & FB_SYNC_HOR_HIGH_ACT))			vid_ctl |= VID_CTL_HS_NHSYNC;		if (!(var->sync & FB_SYNC_VERT_HIGH_ACT))			vid_ctl |= VID_CTL_VS_NVSYNC;	}	sync_len	= var->hsync_len;	display_start	= sync_len + var->left_margin;	display_end	= display_start + var->xres;	cycle		= display_end + var->right_margin;	/* if interlaced, then hcr/2 must be even */	is_interlaced = (var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED;	if (is_interlaced) {		vidc_ctl |= VIDC_CTRL_INTERLACE;		if (cycle & 2) {			cycle += 2;			var->right_margin += 2;		}	}	vidc.h_cycle		= (cycle - 2) / 2;	vidc.h_sync_width	= (sync_len - 2) / 2;	vidc.h_border_start	= (display_start - 1) / 2;	vidc.h_display_start	= (display_start - horiz_correction) / 2;	vidc.h_display_end	= (display_end - horiz_correction) / 2;	vidc.h_border_end	= (display_end - 1) / 2;	vidc.h_interlace	= (vidc.h_cycle + 1) / 2;	sync_len	= var->vsync_len;	display_start	= sync_len + var->upper_margin;	display_end	= display_start + var->yres;	cycle		= display_end + var->lower_margin;	if (is_interlaced)		cycle = (cycle - 3) / 2;	else		cycle = cycle - 1;	vidc.v_cycle		= cycle;	vidc.v_sync_width	= sync_len - 1;	vidc.v_border_start	= display_start - 1;	vidc.v_display_start	= vidc.v_border_start;	vidc.v_display_end	= display_end - 1;	vidc.v_border_end	= vidc.v_display_end;	if (machine_is_a5k())		__raw_writeb(vid_ctl, IOEB_VID_CTL);	if (memcmp(&current_vidc, &vidc, sizeof(vidc))) {		current_vidc = vidc;		vidc_writel(0xe0000000 | vidc_ctl);		vidc_writel(0x80000000 | (vidc.h_cycle << 14));		vidc_writel(0x84000000 | (vidc.h_sync_width << 14));		vidc_writel(0x88000000 | (vidc.h_border_start << 14));		vidc_writel(0x8c000000 | (vidc.h_display_start << 14));		vidc_writel(0x90000000 | (vidc.h_display_end << 14));		vidc_writel(0x94000000 | (vidc.h_border_end << 14));		vidc_writel(0x98000000);		vidc_writel(0x9c000000 | (vidc.h_interlace << 14));		vidc_writel(0xa0000000 | (vidc.v_cycle << 14));		vidc_writel(0xa4000000 | (vidc.v_sync_width << 14));		vidc_writel(0xa8000000 | (vidc.v_border_start << 14));		vidc_writel(0xac000000 | (vidc.v_display_start << 14));		vidc_writel(0xb0000000 | (vidc.v_display_end << 14));		vidc_writel(0xb4000000 | (vidc.v_border_end << 14));		vidc_writel(0xb8000000);		vidc_writel(0xbc000000);	}#ifdef DEBUG_MODE_SELECTION	printk(KERN_DEBUG "VIDC registers for %dx%dx%d:\n", var->xres,	       var->yres, var->bits_per_pixel);	printk(KERN_DEBUG " H-cycle          : %d\n", vidc.h_cycle);	printk(KERN_DEBUG " H-sync-width     : %d\n", vidc.h_sync_width);	printk(KERN_DEBUG " H-border-start   : %d\n", vidc.h_border_start);	printk(KERN_DEBUG " H-display-start  : %d\n", vidc.h_display_start);	printk(KERN_DEBUG " H-display-end    : %d\n", vidc.h_display_end);	printk(KERN_DEBUG " H-border-end     : %d\n", vidc.h_border_end);	printk(KERN_DEBUG " H-interlace      : %d\n", vidc.h_interlace);	printk(KERN_DEBUG " V-cycle          : %d\n", vidc.v_cycle);	printk(KERN_DEBUG " V-sync-width     : %d\n", vidc.v_sync_width);	printk(KERN_DEBUG " V-border-start   : %d\n", vidc.v_border_start);	printk(KERN_DEBUG " V-display-start  : %d\n", vidc.v_display_start);	printk(KERN_DEBUG " V-display-end    : %d\n", vidc.v_display_end);	printk(KERN_DEBUG " V-border-end     : %d\n", vidc.v_border_end);	printk(KERN_DEBUG " VIDC Ctrl (E)    : 0x%08X\n", vidc_ctl);	printk(KERN_DEBUG " IOEB Ctrl        : 0x%08X\n", vid_ctl);#endif}static inline voidacornfb_palette_write(u_int regno, union palette pal){	vidc_writel(pal.p);}static inline union paletteacornfb_palette_encode(u_int regno, u_int red, u_int green, u_int blue,		       u_int trans){	union palette pal;	pal.p = 0;	pal.vidc.reg   = regno;	pal.vidc.red   = red >> 12;	pal.vidc.green = green >> 12;	pal.vidc.blue  = blue >> 12;	return pal;}static voidacornfb_palette_decode(u_int regno, u_int *red, u_int *green, u_int *blue,		       u_int *trans){	*red   = EXTEND4(current_par.palette[regno].vidc.red);	*green = EXTEND4(current_par.palette[regno].vidc.green);	*blue  = EXTEND4(current_par.palette[regno].vidc.blue);	*trans = current_par.palette[regno].vidc.trans ? -1 : 0;}#endif#ifdef HAS_VIDC20#include <asm/arch/acornfb.h>#define MAX_SIZE	2*1024*1024/* VIDC20 has a different set of rules from the VIDC: *  hcr  : must be multiple of 4 *  hswr : must be even *  hdsr : must be even *  hder : must be even *  vcr  : >= 2, (interlace, must be odd) *  vswr : >= 1 *  vdsr : >= 1 *  vder : >= vdsr */static voidacornfb_set_timing(struct fb_var_screeninfo *var){	struct vidc_timing vidc;	u_int vcr, fsize;	u_int ext_ctl, dat_ctl;	u_int words_per_line;	memset(&vidc, 0, sizeof(vidc));	vidc.h_sync_width	= var->hsync_len - 8;	vidc.h_border_start	= vidc.h_sync_width + var->left_margin + 8 - 12;	vidc.h_display_start	= vidc.h_border_start + 12 - 18;	vidc.h_display_end	= vidc.h_display_start + var->xres;	vidc.h_border_end	= vidc.h_display_end + 18 - 12;	vidc.h_cycle		= vidc.h_border_end + var->right_margin + 12 - 8;	vidc.h_interlace	= vidc.h_cycle / 2;	vidc.v_sync_width	= var->vsync_len - 1;	vidc.v_border_start	= vidc.v_sync_width + var->upper_margin;	vidc.v_display_start	= vidc.v_border_start;	vidc.v_display_end	= vidc.v_display_start + var->yres;	vidc.v_border_end	= vidc.v_display_end;	vidc.control		= acornfb_default_control();	vcr = var->vsync_len + var->upper_margin + var->yres +	      var->lower_margin;	if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {		vidc.v_cycle = (vcr - 3) / 2;		vidc.control |= VIDC20_CTRL_INT;	} else		vidc.v_cycle = vcr - 2;	switch (var->bits_per_pixel) {	case  1: vidc.control |= VIDC20_CTRL_1BPP;	break;	case  2: vidc.control |= VIDC20_CTRL_2BPP;	break;	case  4: vidc.control |= VIDC20_CTRL_4BPP;	break;	default:	case  8: vidc.control |= VIDC20_CTRL_8BPP;	break;	case 16: vidc.control |= VIDC20_CTRL_16BPP;	break;	case 32: vidc.control |= VIDC20_CTRL_32BPP;	break;	}	acornfb_vidc20_find_rates(&vidc, var);	fsize = var->vsync_len + var->upper_margin + var->lower_margin - 1;	if (memcmp(&current_vidc, &vidc, sizeof(vidc))) {		current_vidc = vidc;		vidc_writel(VIDC20_CTRL| vidc.control);		vidc_writel(0xd0000000 | vidc.pll_ctl);		vidc_writel(0x80000000 | vidc.h_cycle);		vidc_writel(0x81000000 | vidc.h_sync_width);		vidc_writel(0x82000000 | vidc.h_border_start);		vidc_writel(0x83000000 | vidc.h_display_start);		vidc_writel(0x84000000 | vidc.h_display_end);		vidc_writel(0x85000000 | vidc.h_border_end);		vidc_writel(0x86000000);		vidc_writel(0x87000000 | vidc.h_interlace);		vidc_writel(0x90000000 | vidc.v_cycle);		vidc_writel(0x91000000 | vidc.v_sync_width);		vidc_writel(0x92000000 | vidc.v_border_start);		vidc_writel(0x93000000 | vidc.v_display_start);		vidc_writel(0x94000000 | vidc.v_display_end);		vidc_writel(0x95000000 | vidc.v_border_end);		vidc_writel(0x96000000);		vidc_writel(0x97000000);	}	iomd_writel(fsize, IOMD_FSIZE);	ext_ctl = acornfb_default_econtrol();	if (var->sync & FB_SYNC_COMP_HIGH_ACT) /* should be FB_SYNC_COMP */		ext_ctl |= VIDC20_ECTL_HS_NCSYNC | VIDC20_ECTL_VS_NCSYNC;	else {		if (var->sync & FB_SYNC_HOR_HIGH_ACT)			ext_ctl |= VIDC20_ECTL_HS_HSYNC;		else			ext_ctl |= VIDC20_ECTL_HS_NHSYNC;		if (var->sync & FB_SYNC_VERT_HIGH_ACT)			ext_ctl |= VIDC20_ECTL_VS_VSYNC;		else			ext_ctl |= VIDC20_ECTL_VS_NVSYNC;	}	vidc_writel(VIDC20_ECTL | ext_ctl);	words_per_line = var->xres * var->bits_per_pixel / 32;	if (current_par.using_vram && current_par.screen_size == 2048*1024)		words_per_line /= 2;	/* RiscPC doesn't use the VIDC's VRAM control. */	dat_ctl = VIDC20_DCTL_VRAM_DIS | VIDC20_DCTL_SNA | words_per_line;	/* The data bus width is dependent on both the type	 * and amount of video memory.	 *     DRAM	32bit low	 * 1MB VRAM	32bit	 * 2MB VRAM	64bit	 */	if (current_par.using_vram && current_par.vram_half_sam == 2048) {		dat_ctl |= VIDC20_DCTL_BUS_D63_0;	} else 		dat_ctl |= VIDC20_DCTL_BUS_D31_0;	vidc_writel(VIDC20_DCTL | dat_ctl);#ifdef DEBUG_MODE_SELECTION	printk(KERN_DEBUG "VIDC registers for %dx%dx%d:\n", var->xres,	       var->yres, var->bits_per_pixel);	printk(KERN_DEBUG " H-cycle          : %d\n", vidc.h_cycle);	printk(KERN_DEBUG " H-sync-width     : %d\n", vidc.h_sync_width);	printk(KERN_DEBUG " H-border-start   : %d\n", vidc.h_border_start);	printk(KERN_DEBUG " H-display-start  : %d\n", vidc.h_display_start);	printk(KERN_DEBUG " H-display-end    : %d\n", vidc.h_display_end);	printk(KERN_DEBUG " H-border-end     : %d\n", vidc.h_border_end);	printk(KERN_DEBUG " H-interlace      : %d\n", vidc.h_interlace);	printk(KERN_DEBUG " V-cycle          : %d\n", vidc.v_cycle);	printk(KERN_DEBUG " V-sync-width     : %d\n", vidc.v_sync_width);	printk(KERN_DEBUG " V-border-start   : %d\n", vidc.v_border_start);	printk(KERN_DEBUG " V-display-start  : %d\n", vidc.v_display_start);	printk(KERN_DEBUG " V-display-end    : %d\n", vidc.v_display_end);	printk(KERN_DEBUG " V-border-end     : %d\n", vidc.v_border_end);	printk(KERN_DEBUG " Ext Ctrl  (C)    : 0x%08X\n", ext_ctl);	printk(KERN_DEBUG " PLL Ctrl  (D)    : 0x%08X\n", vidc.pll_ctl);	printk(KERN_DEBUG " Ctrl      (E)    : 0x%08X\n", vidc.control);	printk(KERN_DEBUG " Data Ctrl (F)    : 0x%08X\n", dat_ctl);	printk(KERN_DEBUG " Fsize            : 0x%08X\n", fsize);#endif}static inline voidacornfb_palette_write(u_int regno, union palette pal){	vidc_writel(0x10000000 | regno);	vidc_writel(pal.p);}static inline union paletteacornfb_palette_encode(u_int regno, u_int red, u_int green, u_int blue,		       u_int trans){	union palette pal;	pal.p = 0;	pal.vidc20.red   = red >> 8;	pal.vidc20.green = green >> 8;	pal.vidc20.blue  = blue >> 8;	return pal;}static voidacornfb_palette_decode(u_int regno, u_int *red, u_int *green, u_int *blue,		       u_int *trans){	*red   = EXTEND8(current_par.palette[regno].vidc20.red);	*green = EXTEND8(current_par.palette[regno].vidc20.green);	*blue  = EXTEND8(current_par.palette[regno].vidc20.blue);	*trans = EXTEND4(current_par.palette[regno].vidc20.ext);}#endif/* * Before selecting the timing parameters, adjust * the resolution to fit the rules. */static intacornfb_adjust_timing(struct fb_var_screeninfo *var, int con){	u_int font_line_len;	u_int fontht;	u_int sam_size, min_size, size;	u_int nr_y;	/* xres must be even */	var->xres = (var->xres + 1) & ~1;	/*	 * We don't allow xres_virtual to differ from xres	 */	var->xres_virtual = var->xres;	var->xoffset = 0;	/*	 * Find the font height	 */	if (con == -1)		fontht = fontheight(&global_disp);	else		fontht = fontheight(fb_display + con);	if (fontht == 0)		fontht = 8;	if (current_par.using_vram)		sam_size = current_par.vram_half_sam * 2;	else		sam_size = 16;	/*	 * Now, find a value for yres_virtual which allows	 * us to do ywrap scrolling.  The value of	 * yres_virtual must be such that the end of the	 * displayable frame buffer must be aligned with	 * the start of a font line.	 */	font_line_len = var->xres * var->bits_per_pixel * fontht / 8;	min_size = var->xres * var->yres * var->bits_per_pixel / 8;

⌨️ 快捷键说明

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