sstfb.c

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

C
1,724
字号
/* * linux/drivers/video/sstfb.c -- voodoo graphics frame buffer * *     Copyright (c) 2000-2002 Ghozlane Toumi <gtoumi@laposte.net> * *     Created 15 Jan 2000 by Ghozlane Toumi * * Contributions (and many thanks) : * * 03/2001 James Simmons   <jsimmons@infradead.org> * 04/2001 Paul Mundt      <lethal@chaoticdreams.org> * 05/2001 Urs Ganse       <ursg@uni.de> *	(initial work on voodoo2 port, interlace) * 09/2002 Helge Deller    <deller@gmx.de> *	(enable driver on big-endian machines (hppa), ioctl fixes) * 12/2002 Helge Deller    <deller@gmx.de> *	(port driver to new frambuffer infrastructure) * 01/2003 Helge Deller    <deller@gmx.de> *	(initial work on fb hardware acceleration for voodoo2) * *//* * The voodoo1 has the following memory mapped address space: * 0x000000 - 0x3fffff : registers              (4MB) * 0x400000 - 0x7fffff : linear frame buffer    (4MB) * 0x800000 - 0xffffff : texture memory         (8MB) *//* * misc notes, TODOs, toASKs, and deep thoughts-TODO: at one time or another test that the mode is acceptable by the monitor-ASK: Can I choose different ordering for the color bitfields (rgba argb ...)      wich one should i use ? is there any preferred one ? It seems ARGB is      the one ...-TODO: in  set_var check the validity of timings (hsync vsync)...-TODO: check and recheck the use of sst_wait_idle : we don't flush the fifo via       a nop command. so it's ok as long as the commands we pass don't go       through the fifo. warning: issuing a nop command seems to need pci_fifo-FIXME: in case of failure in the init sequence, be sure we return to a safe        state.-FIXME: 4MB boards have banked memory (FbiInit2 bits 1 & 20) *//* * debug info * SST_DEBUG : enable debugging * SST_DEBUG_REG : debug registers *   0 :  no debug *   1 : dac calls, [un]set_bits, FbiInit *   2 : insane debug level (log every register read/write) * SST_DEBUG_FUNC : functions *   0 : no debug *   1 : function call / debug ioctl *   2 : variables *   3 : flood . you don't want to do that. trust me. * SST_DEBUG_VAR : debug display/var structs *   0 : no debug *   1 : dumps display, fb_var * * sstfb specific ioctls: *   		toggle vga (0x46db) : toggle vga_pass_through *   		fill fb    (0x46dc) : fills fb *   		test disp  (0x46de) : draws a test image */#undef SST_DEBUG#define SST_DEBUG_REG   0#define SST_DEBUG_FUNC  0#define SST_DEBUG_VAR   0/* enable 24/32 bpp functions ? (completely untested!) */#undef EN_24_32_BPP/*  Default video mode .  0 800x600@60  took from glide  1 640x480@75  took from glide  2 1024x768@76 std fb.mode  3 640x480@60  glide default */#define DEFAULT_MODE 3 /* * Includes */#include <linux/config.h>#include <linux/string.h>#include <linux/kernel.h>#include <linux/module.h>#include <linux/fb.h>#include <linux/pci.h>#include <linux/delay.h>#include <linux/init.h>#include <linux/slab.h>#include <asm/io.h>#include <asm/ioctl.h>#include <asm/uaccess.h>#include <video/sstfb.h>/* initialized by setup */static int vgapass;		/* enable Vga passthrough cable */static int mem;			/* mem size in MB, 0 = autodetect */static int clipping = 1;	/* use clipping (slower, safer) */static int gfxclk;		/* force FBI freq in Mhz . Dangerous */static int slowpci;		/* slow PCI settings */static char *mode_option __devinitdata;enum {	ID_VOODOO1 = 0,	ID_VOODOO2 = 1,};#define IS_VOODOO2(par) ((par)->type == ID_VOODOO2)static struct sst_spec voodoo_spec[] __devinitdata = { { .name = "Voodoo Graphics", .default_gfx_clock = 50000, .max_gfxclk = 60 }, { .name = "Voodoo2",	      .default_gfx_clock = 75000, .max_gfxclk = 85 },};static struct fb_var_screeninfo	sstfb_default =#if ( DEFAULT_MODE == 0 )    { /* 800x600@60, 16 bpp .borowed from glide/sst1/include/sst1init.h */    800, 600, 800, 600, 0, 0, 16, 0,    {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0},    0, 0, -1, -1, 0,    25000, 86, 41, 23, 1, 127, 4,    0, FB_VMODE_NONINTERLACED };#elif ( DEFAULT_MODE == 1 )    {/* 640x480@75, 16 bpp .borowed from glide/sst1/include/sst1init.h */    640, 480, 640, 480, 0, 0, 16, 0,    {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0},    0, 0, -1, -1, 0,    31746, 118, 17, 16, 1, 63, 3,    0, FB_VMODE_NONINTERLACED };#elif ( DEFAULT_MODE == 2 )    { /* 1024x768@76 took from my /etc/fb.modes */    1024, 768, 1024, 768,0, 0, 16,0,    {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0},    0, 0, -1, -1, 0,    11764, 208, 8, 36, 16, 120, 3 ,    0, FB_VMODE_NONINTERLACED };#elif ( DEFAULT_MODE == 3 )    { /* 640x480@60 , 16bpp glide default ?*/    640, 480, 640, 480, 0, 0, 16, 0,    {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0},    0, 0, -1, -1, 0,    39721 ,  38, 26 ,  25 ,18  , 96 ,2,    0, FB_VMODE_NONINTERLACED };#elif    #error "Invalid DEFAULT_MODE value !"#endif/* * debug functions */static void sstfb_drawdebugimage(struct fb_info *info);static int sstfb_dump_regs(struct fb_info *info);#if (SST_DEBUG_REG > 0)static void sst_dbg_print_read_reg(u32 reg, u32 val) {	const char *regname;	switch (reg) {	case FBIINIT0:	regname = "FbiInit0"; break;	case FBIINIT1:	regname = "FbiInit1"; break;	case FBIINIT2:	regname = "FbiInit2"; break;	case FBIINIT3:	regname = "FbiInit3"; break;	case FBIINIT4:	regname = "FbiInit4"; break;	case FBIINIT5:	regname = "FbiInit5"; break;	case FBIINIT6:	regname = "FbiInit6"; break;	default:	regname = NULL;       break;	}	if (regname == NULL)		r_ddprintk("sst_read(%#x): %#x\n", reg, val);	else		r_dprintk(" sst_read(%s): %#x\n", regname, val);}static void sst_dbg_print_write_reg(u32 reg, u32 val) {	const char *regname;	switch (reg) {	case FBIINIT0:	regname = "FbiInit0"; break;	case FBIINIT1:	regname = "FbiInit1"; break;	case FBIINIT2:	regname = "FbiInit2"; break;	case FBIINIT3:	regname = "FbiInit3"; break;	case FBIINIT4:	regname = "FbiInit4"; break;	case FBIINIT5:	regname = "FbiInit5"; break;	case FBIINIT6:	regname = "FbiInit6"; break;	default:	regname = NULL;       break;	}	if (regname == NULL)		r_ddprintk("sst_write(%#x, %#x)\n", reg, val);	else		r_dprintk(" sst_write(%s, %#x)\n", regname, val);}#else /*  (SST_DEBUG_REG > 0) */#  define sst_dbg_print_read_reg(reg, val)	do {} while(0)#  define sst_dbg_print_write_reg(reg, val)	do {} while(0)#endif /*  (SST_DEBUG_REG > 0) *//* * hardware access functions *//* register access */#define sst_read(reg)		__sst_read(par->mmio_vbase, reg)#define sst_write(reg,val)	__sst_write(par->mmio_vbase, reg, val)#define sst_set_bits(reg,val)	__sst_set_bits(par->mmio_vbase, reg, val)#define sst_unset_bits(reg,val)	__sst_unset_bits(par->mmio_vbase, reg, val)#define sst_dac_read(reg)	__sst_dac_read(par->mmio_vbase, reg)#define sst_dac_write(reg,val)	__sst_dac_write(par->mmio_vbase, reg, val)#define dac_i_read(reg)		__dac_i_read(par->mmio_vbase, reg)#define dac_i_write(reg,val)	__dac_i_write(par->mmio_vbase, reg, val)static inline u32 __sst_read(u_long vbase, u32 reg){	u32 ret = readl(vbase + reg);	sst_dbg_print_read_reg(reg, ret);	return ret;}static inline void __sst_write(u_long vbase, u32 reg, u32 val){	sst_dbg_print_write_reg(reg, val);	writel(val, vbase + reg);}static inline void __sst_set_bits(u_long vbase, u32 reg, u32 val){	r_dprintk("sst_set_bits(%#x, %#x)\n", reg, val);	__sst_write(vbase, reg, __sst_read(vbase, reg) | val);}static inline void __sst_unset_bits(u_long vbase, u32 reg, u32 val){	r_dprintk("sst_unset_bits(%#x, %#x)\n", reg, val);	__sst_write(vbase, reg, __sst_read(vbase, reg) & ~val);}/* * wait for the fbi chip. ASK: what happens if the fbi is stuck ? * * the FBI is supposed to be ready if we receive 5 time * in a row a "idle" answer to our requests */#define sst_wait_idle() __sst_wait_idle(par->mmio_vbase)static int __sst_wait_idle(u_long vbase){	int count = 0;	/* if (doFBINOP) __sst_write(vbase, NOPCMD, 0); */	while(1) {		if (__sst_read(vbase, STATUS) & STATUS_FBI_BUSY) {			f_dddprintk("status: busy\n");/* FIXME basicaly, this is a busy wait. maybe not that good. oh well; * this is a small loop after all. * Or maybe we should use mdelay() or udelay() here instead ? */			count = 0;		} else {			count++;			f_dddprintk("status: idle(%d)\n", count);		}		if (count >= 5) return 1;/* XXX  do something to avoid hanging the machine if the voodoo is out */	}}/* dac access *//* dac_read should be remaped to FbiInit2 (via the pci reg init_enable) */static u8 __sst_dac_read(u_long vbase, u8 reg){	u8 ret;	reg &= 0x07;	__sst_write(vbase, DAC_DATA, ((u32)reg << 8) | DAC_READ_CMD );	__sst_wait_idle(vbase);	/* udelay(10); */	ret = __sst_read(vbase, DAC_READ) & 0xff;	r_dprintk("sst_dac_read(%#x): %#x\n", reg, ret);	return ret;}static void __sst_dac_write(u_long vbase, u8 reg, u8 val){	r_dprintk("sst_dac_write(%#x, %#x)\n", reg, val);	reg &= 0x07;	__sst_write(vbase, DAC_DATA,(((u32)reg << 8)) | (u32)val);}/* indexed access to ti/att dacs */static u32 __dac_i_read(u_long vbase, u8 reg){	u32 ret;	__sst_dac_write(vbase, DACREG_ADDR_I, reg);	ret = __sst_dac_read(vbase, DACREG_DATA_I);	r_dprintk("sst_dac_read_i(%#x): %#x\n", reg, ret);	return ret;}static void __dac_i_write(u_long vbase, u8 reg,u8 val){	r_dprintk("sst_dac_write_i(%#x, %#x)\n", reg, val);	__sst_dac_write(vbase, DACREG_ADDR_I, reg);	__sst_dac_write(vbase, DACREG_DATA_I, val);}/* compute the m,n,p  , returns the real freq * (ics datasheet :  N <-> N1 , P <-> N2) * * Fout= Fref * (M+2)/( 2^P * (N+2)) *  we try to get close to the asked freq *  with P as high, and M as low as possible * range: * ti/att : 0 <= M <= 255; 0 <= P <= 3; 0<= N <= 63 * ics    : 1 <= M <= 127; 0 <= P <= 3; 1<= N <= 31 * we'll use the lowest limitation, should be precise enouth */static int sst_calc_pll(const int freq, int *freq_out, struct pll_timing *t){	int m, m2, n, p, best_err, fout;	int best_n = -1;	int best_m = -1;	best_err = freq;	p = 3;	/* f * 2^P = vco should be less than VCOmax ~ 250 MHz for ics*/	while (((1 << p) * freq > VCO_MAX) && (p >= 0))		p--;	if (p == -1)		return -EINVAL;	for (n = 1; n < 32; n++) {		/* calc 2 * m so we can round it later*/		m2 = (2 * freq * (1 << p) * (n + 2) ) / DAC_FREF - 4 ;		m = (m2 % 2 ) ? m2/2+1 : m2/2 ;		if (m >= 128)			break;		fout = (DAC_FREF * (m + 2)) / ((1 << p) * (n + 2));		if ((abs(fout - freq) < best_err) && (m > 0)) {			best_n = n;			best_m = m;			best_err = abs(fout - freq);			/* we get the lowest m , allowing 0.5% error in freq*/			if (200*best_err < freq) break;		}	}	if (best_n == -1)  /* unlikely, but who knows ? */		return -EINVAL;	t->p = p;	t->n = best_n;	t->m = best_m;	*freq_out = (DAC_FREF * (t->m + 2)) / ((1 << t->p) * (t->n + 2));	f_ddprintk ("m: %d, n: %d, p: %d, F: %dKhz\n",		  t->m, t->n, t->p, *freq_out);	return 0;}/* * clear lfb screen */static void sstfb_clear_screen(struct fb_info *info){	/* clear screen */	fb_memset(info->screen_base, 0, info->fix.smem_len);}/** *      sstfb_check_var - Optional function.  Validates a var passed in. *      @var: frame buffer variable screen structure *      @info: frame buffer structure that represents a single frame buffer */static int sstfb_check_var(struct fb_var_screeninfo *var,		struct fb_info *info){	struct sstfb_par *par = (struct sstfb_par *) info->par;	int hSyncOff   = var->xres + var->right_margin + var->left_margin;	int vSyncOff   = var->yres + var->lower_margin + var->upper_margin;	int vBackPorch = var->left_margin, yDim = var->yres;	int vSyncOn    = var->vsync_len;	int tiles_in_X, real_length;	unsigned int freq;	if (sst_calc_pll(PICOS2KHZ(var->pixclock), &freq, &par->pll)) {		eprintk("Pixclock at %ld KHZ out of range\n",				PICOS2KHZ(var->pixclock));		return -EINVAL;	}	var->pixclock = KHZ2PICOS(freq);		if (var->vmode & FB_VMODE_INTERLACED)		vBackPorch += (vBackPorch % 2);	if (var->vmode & FB_VMODE_DOUBLE) {		vBackPorch <<= 1;		yDim <<=1;		vSyncOn <<=1;		vSyncOff <<=1;	}	switch (var->bits_per_pixel) {	case 0 ... 16 :		var->bits_per_pixel = 16;		break;#ifdef EN_24_32_BPP	case 17 ... 24 :		var->bits_per_pixel = 24;		break;	case 25 ... 32 :		var->bits_per_pixel = 32;		break;#endif	default :		eprintk("Unsupported bpp %d\n", var->bits_per_pixel);		return -EINVAL;	}		/* validity tests */	if ((var->xres <= 1) || (yDim <= 0 )

⌨️ 快捷键说明

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