📄 epson1356fb.c
字号:
/* * epson1356fb.c -- Epson SED1356 Framebuffer Driver * * Copyright 2001, 2002, 2003 MontaVista Software Inc. * Author: MontaVista Software, Inc. * stevel@mvista.com or source@mvista.com * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 675 Mass Ave, Cambridge, MA 02139, USA. * * * TODO: * * Revision history * 03.12.2001 0.1 Initial release * */#include <linux/config.h>#include <linux/version.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/errno.h>#include <linux/string.h>#include <linux/mm.h>#include <linux/tty.h>#include <linux/slab.h>#include <linux/vmalloc.h>#include <linux/delay.h>#include <linux/interrupt.h>#include <linux/fb.h>#include <linux/selection.h>#include <linux/console.h>#include <linux/init.h>#include <linux/pci.h>#include <linux/nvram.h>#include <linux/kd.h>#include <linux/vt_kern.h>#include <asm/io.h>#include <asm/uaccess.h>#include <linux/timer.h>#include <linux/pagemap.h>#include <asm/pgalloc.h>#include <asm/uaccess.h>#include <asm/tlb.h>#ifdef CONFIG_MTRR#include <asm/mtrr.h>#endif#include <video/fbcon.h>#include <video/fbcon-cfb8.h>#include <video/fbcon-cfb16.h>#include <video/fbcon-cfb24.h>#include <video/fbcon-cfb32.h>#include <linux/spinlock.h>#include <video/e1356fb.h>#ifdef CONFIG_SOC_AU1X00#include <asm/au1000.h>#endif#define E1356FB_DEBUG 1#undef E1356FB_VERBOSE_DEBUG#undef SHADOW_FRAME_BUFFER#include "epson1356fb.h"static char *options;MODULE_PARM(options, "s");/* * Frame buffer device API */static int e1356fb_open(struct fb_info *fb, int user);static int e1356fb_release(struct fb_info *fb, int user);static int e1356fb_get_fix(struct fb_fix_screeninfo* fix, int con, struct fb_info* fb);static int e1356fb_get_var(struct fb_var_screeninfo* var, int con, struct fb_info* fb);static int e1356fb_set_var(struct fb_var_screeninfo* var, int con, struct fb_info* fb);static int e1356fb_pan_display(struct fb_var_screeninfo* var, int con, struct fb_info* fb);static int e1356fb_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info* info);static int e1356fb_set_cmap(struct fb_cmap* cmap, int kspc, int con, struct fb_info* info);static int e1356fb_ioctl(struct inode* inode, struct file* file, u_int cmd, u_long arg, int con, struct fb_info* info);static int e1356fb_mmap(struct fb_info *info, struct file *file, struct vm_area_struct *vma);/* * Interface to the low level console driver */static int e1356fb_switch_con(int con, struct fb_info* fb);static int e1356fb_updatevar(int con, struct fb_info* fb);static void e1356fb_blank(int blank, struct fb_info* fb);/* * Internal routines */static void e1356fb_set_par(const struct e1356fb_par* par, struct fb_info_e1356* info);static int e1356fb_var_to_par(const struct fb_var_screeninfo *var, struct e1356fb_par* par, const struct fb_info_e1356* info);static int e1356fb_par_to_var(struct fb_var_screeninfo* var, struct e1356fb_par* par, const struct fb_info_e1356* info);static int e1356fb_encode_fix(struct fb_fix_screeninfo* fix, const struct e1356fb_par* par, const struct fb_info_e1356* info);static void e1356fb_set_dispsw(struct display* disp, struct fb_info_e1356* info, int bpp, int accel);static int e1356fb_getcolreg(u_int regno, u_int* red, u_int* green, u_int* blue, u_int* transp, struct fb_info* fb);static int e1356fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, u_int transp, struct fb_info* fb);static void e1356fb_install_cmap(struct display *d, struct fb_info *info);static void e1356fb_hwcursor_init(struct fb_info_e1356* info);static void e1356fb_createcursorshape(struct display* p);static void e1356fb_createcursor(struct display * p); /* * do_xxx: Hardware-specific functions */static void do_pan_var(struct fb_var_screeninfo* var, struct fb_info_e1356* i);static void do_flashcursor(unsigned long ptr);static void doBlt_Move(const struct e1356fb_par* par, struct fb_info_e1356* i, blt_info_t* blt);static void doBlt_SolidFill(const struct e1356fb_par* par, struct fb_info_e1356* i, blt_info_t* blt);/* * Interface used by the world */int e1356fb_init(void);void e1356fb_setup(char *options, int *ints);static int currcon = 0;static struct fb_ops e1356fb_ops = { owner: THIS_MODULE, fb_open: e1356fb_open, fb_release: e1356fb_release, fb_get_fix: e1356fb_get_fix, fb_get_var: e1356fb_get_var, fb_set_var: e1356fb_set_var, fb_get_cmap: e1356fb_get_cmap, fb_set_cmap: e1356fb_set_cmap, fb_pan_display: e1356fb_pan_display, fb_ioctl: e1356fb_ioctl, fb_mmap: e1356fb_mmap,};#define PCI_VENDOR_ID_EPSON 0x10f4#define PCI_DEVICE_ID_EPSON_SDU1356 0x1300static struct fb_info_e1356 fb_info;static struct e1356fb_fix boot_fix; // boot optionsstatic struct e1356fb_par boot_par; // boot options/* ------------------------------------------------------------------------- * Hardware-specific funcions * ------------------------------------------------------------------------- *//* * The SED1356 has only a 16-bit wide data bus, so some embedded * implementations with 32-bit CPU's (Alchemy Pb1000) may not * correctly emulate a 32-bit write to the framebuffer by splitting * the write into two seperate 16-bit writes. So it is safest to * only do byte or half-word writes to the fb. This routine assumes * fbaddr is atleast aligned on a half-word boundary. */static inline voidfbfill(u16* fbaddr, u8 val, int size){ u16 valw = (u16)val | ((u16)val << 8); for ( ; size >= 2; size -= 2) writew(valw, fbaddr++); if (size) writeb(val, (u8*)fbaddr);}static inline inte1356_wait_bitclr(u8* reg, u8 bit, int timeout){ while (readb(reg) & bit) { udelay(10); if (!--timeout) break; } return timeout;}static inline inte1356_wait_bitset(u8* reg, u8 bit, int timeout){ while (!(readb(reg) & bit)) { udelay(10); if (!--timeout) break; } return timeout;}static struct fb_videomode panel_modedb[] = { { /* 320x240 @ 109 Hz, 33.3 kHz hsync */ NULL, 109, 320, 240, KHZ2PICOS(MAX_PIXCLOCK/3), 16, 16, 32, 24, 48, 8, 0, FB_VMODE_NONINTERLACED }, { /* 640x480 @ 84 Hz, 48.1 kHz hsync */ NULL, 84, 640, 480, KHZ2PICOS(MAX_PIXCLOCK/1), 96, 32, 32, 48, 64, 8, 0, FB_VMODE_NONINTERLACED }, { /* 800x600 @ 76 Hz, 46.3 kHz hsync */ NULL, 76, 800, 600, KHZ2PICOS(MAX_PIXCLOCK/1), 32, 10, 1, 1, 22, 1, 0, FB_VMODE_NONINTERLACED }};static struct fb_videomode crt_modedb[] = { { /* 320x240 @ 84 Hz, 31.25 kHz hsync */ NULL, 84, 320, 240, KHZ2PICOS(MAX_PIXCLOCK/2), 128, 128, 60, 60, 64, 8, 0, FB_VMODE_NONINTERLACED }, { /* 320x240 @ 109 Hz, 33.3 kHz hsync */ NULL, 109, 320, 240, KHZ2PICOS(MAX_PIXCLOCK/3), 16, 16, 32, 24, 48, 8, 0, FB_VMODE_NONINTERLACED }, { /* 512x384 @ 77 Hz, 31.25 kHz hsync */ NULL, 77, 512, 384, KHZ2PICOS(MAX_PIXCLOCK/2), 48, 16, 16, 1, 64, 3, 0, FB_VMODE_NONINTERLACED }, { /* 640x400 @ 88 Hz, 43.1 kHz hsync */ NULL, 88, 640, 400, KHZ2PICOS(MAX_PIXCLOCK/1), 128, 96, 32, 48, 64, 8, 0, FB_VMODE_NONINTERLACED }, { /* 640x480 @ 84 Hz, 48.1 kHz hsync */ NULL, 84, 640, 480, KHZ2PICOS(MAX_PIXCLOCK/1), 96, 32, 32, 48, 64, 8, 0, FB_VMODE_NONINTERLACED }, { /* 768x576 @ 62 Hz, 38.5 kHz hsync */ NULL, 62, 768, 576, KHZ2PICOS(MAX_PIXCLOCK/1), 144, 16, 28, 6, 112, 4, 0, FB_VMODE_NONINTERLACED }, { /* 800x600 @ 60 Hz, 37.9 kHz hsync */ NULL, 60, 800, 600, KHZ2PICOS(MAX_PIXCLOCK/1), 88, 40, 23, 1, 128, 4, FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED }};static struct fb_videomode ntsc_modedb[] = { { /* 640x480 @ 62 Hz, requires flicker filter */ //NULL, 62, 640, 480, 34921, 213, 57, 20, 2, 0, 0, NULL, 62, 640, 480, KHZ2PICOS(2*NTSC_PIXCLOCK), 200, 70, 15, 7, 0, 0, FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED }};static struct fb_videomode pal_modedb[] = { { /* 640x480 @ 56 Hz, requires flicker filter */ NULL, 56, 640, 480, KHZ2PICOS(2*PAL_PIXCLOCK), 350, 145, 49, 23, 0, 0, FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED }};static inline voidfb_videomode_to_var(struct fb_videomode* mode, struct fb_var_screeninfo*var){ var->xres = mode->xres; var->yres = mode->yres; var->pixclock = mode->pixclock; var->left_margin = mode->left_margin; var->right_margin = mode->right_margin; var->upper_margin = mode->upper_margin; var->lower_margin = mode->lower_margin; var->hsync_len = mode->hsync_len; var->vsync_len = mode->vsync_len; var->sync = mode->sync; var->vmode = mode->vmode;}static inte1356fb_get_mode(const struct fb_info_e1356 *info, int xres, int yres, struct fb_videomode ** modedb, struct fb_videomode ** mode){ struct fb_videomode * ret; int i, dbsize; if (IS_PANEL(info->fix.disp_type)) { ret = panel_modedb; dbsize = sizeof(panel_modedb)/sizeof(struct fb_videomode); } else if (info->fix.disp_type == DISP_TYPE_CRT) { ret = crt_modedb; dbsize = sizeof(crt_modedb)/sizeof(struct fb_videomode); } else if (info->fix.disp_type == DISP_TYPE_NTSC) { ret = ntsc_modedb; dbsize = sizeof(ntsc_modedb)/sizeof(struct fb_videomode); } else { ret = pal_modedb; dbsize = sizeof(pal_modedb)/sizeof(struct fb_videomode); } if (modedb) *modedb = ret; for (i=0; i<dbsize; i++) { if (xres == ret[i].xres && yres == ret[i].yres) { *mode = &ret[i]; break; } } if (i == dbsize) return -EINVAL; return dbsize;}#ifdef E1356FB_VERBOSE_DEBUGstatic voiddump_par(const struct e1356fb_par* par){ DPRINTK("width: %d\n", par->width); DPRINTK("height: %d\n", par->height); DPRINTK("width_virt: %d\n", par->width_virt); DPRINTK("height_virt: %d\n", par->height_virt); DPRINTK("bpp: %d\n", par->bpp); DPRINTK("pixclock: %d\n", par->ipclk.pixclk); DPRINTK("horiz_ndp: %d\n", par->horiz_ndp); DPRINTK("vert_ndp: %d\n", par->vert_ndp); DPRINTK("hsync_pol: %d\n", par->hsync_pol); DPRINTK("hsync_start: %d\n", par->hsync_start); DPRINTK("hsync_width: %d\n", par->hsync_width); DPRINTK("vsync_pol: %d\n", par->vsync_pol); DPRINTK("vsync_start: %d\n", par->vsync_start); DPRINTK("vsync_width: %d\n", par->vsync_width); DPRINTK("cmap_len: %d\n", par->cmap_len);}static voiddump_display_regs(reg_dispcfg_t* dispcfg, reg_dispmode_t* dispmode){ DPRINTK("hdw: 0x%02x\n", readb(&dispcfg->hdw)); DPRINTK("hndp: 0x%02x\n", readb(&dispcfg->hndp)); DPRINTK("hsync_start: 0x%02x\n", readb(&dispcfg->hsync_start)); DPRINTK("hsync_pulse: 0x%02x\n", readb(&dispcfg->hsync_pulse)); DPRINTK("vdh0: 0x%02x\n", readb(&dispcfg->vdh0)); DPRINTK("vdh1: 0x%02x\n", readb(&dispcfg->vdh1)); DPRINTK("vndp: 0x%02x\n", readb(&dispcfg->vndp)); DPRINTK("vsync_start: 0x%02x\n", readb(&dispcfg->vsync_start)); DPRINTK("vsync_pulse: 0x%02x\n", readb(&dispcfg->vsync_pulse)); DPRINTK("tv_output_ctrl: 0x%02x\n\n", readb(&dispcfg->tv_output_ctrl)); DPRINTK("disp_mode: 0x%02x\n", readb(&dispmode->disp_mode)); DPRINTK("lcd_misc: 0x%02x\n", readb(&dispmode->lcd_misc)); DPRINTK("start_addr0: 0x%02x\n", readb(&dispmode->start_addr0)); DPRINTK("start_addr1: 0x%02x\n", readb(&dispmode->start_addr1)); DPRINTK("start_addr2: 0x%02x\n", readb(&dispmode->start_addr2)); DPRINTK("mem_addr_offset0: 0x%02x\n", readb(&dispmode->mem_addr_offset0)); DPRINTK("mem_addr_offset1: 0x%02x\n", readb(&dispmode->mem_addr_offset1)); DPRINTK("pixel_panning: 0x%02x\n", readb(&dispmode->pixel_panning)); DPRINTK("fifo_high_thresh: 0x%02x\n", readb(&dispmode->fifo_high_thresh)); DPRINTK("fifo_low_thresh: 0x%02x\n", readb(&dispmode->fifo_low_thresh));}static voiddump_fb(u8* base, int len){ int i; DPRINTK("FB memory dump, start 0x%p, len %d", base, len); for (i=0; i<len; i++) { if (!(i%16)) printk("\n%p: %02x ", &base[i], readb(&base[i])); else printk("%02x ", readb(&base[i])); } printk("\n");}#endif // E1356FB_VERBOSE_DEBUG// Input: ipclk->clksrc, ipclk->pixclk_d// Output: ipclk->pixclk, ipclk->error, and ipclk->divisorstatic intget_nearest_pixclk_div(pixclock_info_t* ipclk, int x2){ int pixclk_d = ipclk->pixclk_d; int clksrc = ipclk->clksrc; if (x2) clksrc *= 2; if (clksrc < (3*pixclk_d+1)/2) ipclk->divisor = 1; else if (clksrc < (5*pixclk_d+1)/2) ipclk->divisor = 2; else if (clksrc < (7*pixclk_d+1)/2) ipclk->divisor = 3; else if (clksrc < (9*pixclk_d+1)/2) ipclk->divisor = 4; else return -ENXIO; ipclk->pixclk = clksrc / ipclk->divisor; ipclk->error = (100*(pixclk_d - ipclk->pixclk)) / pixclk_d; return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -