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 + -
显示快捷键?