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

📄 acornfb.c

📁 Linux环境下视频显示卡设备的驱动程序源代码
💻 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?) * * FIXME: (things broken by the "new improved" FBCON API) *  - Blanking 8bpp displays with VIDC */#include <linux/module.h>#include <linux/kernel.h>#include <linux/errno.h>#include <linux/string.h>#include <linux/ctype.h>#include <linux/slab.h>#include <linux/mm.h>#include <linux/init.h>#include <linux/fb.h>#include <linux/platform_device.h>#include <linux/dma-mapping.h>#include <mach/hardware.h>#include <asm/io.h>#include <asm/irq.h>#include <asm/mach-types.h>#include <asm/pgtable.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#define DEFAULT_BPP	4/* * 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 = {	{	/* TV		*/		.hfmin	= 15469,		.hfmax	= 15781,		.vfmin	= 49,		.vfmax	= 51,	}, {	/* Multi Freq	*/		.hfmin	= 0,		.hfmax	= 99999,		.vfmin	= 0,		.vfmax	= 199,	}, {	/* Hi-res mono	*/		.hfmin	= 58608,		.hfmax	= 58608,		.vfmin	= 64,		.vfmax	= 64,	}, {	/* VGA		*/		.hfmin	= 30000,		.hfmax	= 70000,		.vfmin	= 60,		.vfmax	= 60,	}, {	/* SVGA		*/		.hfmin	= 30000,		.hfmax	= 70000,		.vfmin	= 56,		.vfmax	= 75,	}, {		.hfmin	= 30000,		.hfmax	= 70000,		.vfmin	= 60,		.vfmax	= 60,	}};static struct fb_info fb_info;static struct acornfb_par current_par;static struct vidc_timing current_vidc;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 */};static struct pixclock *acornfb_valid_pixrate(struct fb_var_screeninfo *var){	u_long pixclock = var->pixclock;	u_int i;	if (!var->pixclock)		return NULL;	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;	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);	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 intacornfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,		  u_int trans, struct fb_info *info){	union palette pal;	if (regno >= current_par.palette_size)		return 1;	pal.p = 0;	pal.vidc.reg   = regno;	pal.vidc.red   = red >> 12;	pal.vidc.green = green >> 12;	pal.vidc.blue  = blue >> 12;	current_par.palette[regno] = pal;	vidc_writel(pal.p);	return 0;}#endif#ifdef HAS_VIDC20#include <mach/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 void acornfb_set_timing(struct fb_info *info){	struct fb_var_screeninfo *var = &info->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 && info->fix.smem_len == 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);

⌨️ 快捷键说明

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