📄 s3c44b0xfb.c
字号:
/* * linux/drivers/video/s3c44b0fb.c * * tpu. * * 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 program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Framebuffer driver for the S3C44B0X processors. *///#ifndef CONFIG_FBCON_CFB8#define LCD_GRAY_16//#endif#include <linux/module.h>#include <linux/kernel.h>#include <linux/slab.h>#include <linux/fb.h>#include <linux/init.h>#include <video/fbcon.h>#ifdef LCD_GRAY_16#include <video/fbcon-cfb4.h>#else#include <video/fbcon-cfb8.h>#endif#include <asm/hardware.h>#include <asm/mach-types.h>#include <asm/uaccess.h>static struct s3c44b0fb_info { struct fb_info fb; int currcon;} *cfb;#define CMAP_SIZE 256/* * Set a single color register. Return != 0 for invalid regno. */static ints3c44b0fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, u_int transp, struct fb_info *info){ //TODO return 0;}/* * Set the colormap */static ints3c44b0fb_set_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info){ struct s3c44b0fb_info *cfb = (struct s3c44b0fb_info *)info; struct fb_cmap *dcmap = &fb_display[con].cmap; int err = 0; /* no colormap allocated? */ if (!dcmap->len) err = fb_alloc_cmap(dcmap, CMAP_SIZE, 0); if (!err && con == cfb->currcon) { err = fb_set_cmap(cmap, kspc, s3c44b0fb_setcolreg, &cfb->fb); dcmap = &cfb->fb.cmap; } if (!err) fb_copy_cmap(cmap, dcmap, kspc ? 0 : 1); return err;}/* * Set the User Defined Part of the Display */static ints3c44b0fb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info){ struct display *display; unsigned int lcdcon, syscon; int chgvar = 0; if (var->activate & FB_ACTIVATE_TEST) return 0; if ((var->activate & FB_ACTIVATE_MASK) != FB_ACTIVATE_NOW) return -EINVAL; if (cfb->fb.var.xres != var->xres) chgvar = 1; if (cfb->fb.var.yres != var->yres) chgvar = 1; if (cfb->fb.var.xres_virtual != var->xres_virtual) chgvar = 1; if (cfb->fb.var.yres_virtual != var->yres_virtual) chgvar = 1; if (cfb->fb.var.bits_per_pixel != var->bits_per_pixel) chgvar = 1; if (con < 0) { display = cfb->fb.disp; chgvar = 0; } else { display = fb_display + con; } var->transp.msb_right = 0; var->transp.offset = 0; var->transp.length = 0; var->red.msb_right = 5;//0; var->red.offset = 5; var->red.length = 3; var->green.msb_right = 2;//0; var->green.offset = 2; var->green.length = 3; var->blue.msb_right = 0; var->blue.offset = 0; var->blue.length = 2; switch (var->bits_per_pixel) {#ifdef FBCON_HAS_MFB case 1: cfb->fb.fix.visual = FB_VISUAL_MONO01; display->dispsw = &fbcon_mfb; display->dispsw_data = NULL; break;#endif#ifdef FBCON_HAS_CFB2 case 2: cfb->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR; display->dispsw = &fbcon_cfb2; display->dispsw_data = NULL; break;#endif#ifdef FBCON_HAS_CFB4 case 4: cfb->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR; display->dispsw = &fbcon_cfb4; // display->dispsw->set_font(display,8,16); display->dispsw_data = NULL; break;#endif#ifdef FBCON_HAS_CFB8 case 8: cfb->fb.fix.visual = FB_VISUAL_TRUECOLOR; display->dispsw = &fbcon_cfb8; display->dispsw_data = NULL; break;#endif default: return -EINVAL; } display->next_line = var->xres_virtual * var->bits_per_pixel / 8; cfb->fb.fix.line_length = display->next_line; display->screen_base = cfb->fb.screen_base; display->line_length = cfb->fb.fix.line_length; display->visual = cfb->fb.fix.visual; display->type = cfb->fb.fix.type; display->type_aux = cfb->fb.fix.type_aux; display->ypanstep = cfb->fb.fix.ypanstep; display->ywrapstep = cfb->fb.fix.ywrapstep; display->can_soft_blank = 1; display->inverse = 0; cfb->fb.var = *var; cfb->fb.var.activate &= ~FB_ACTIVATE_ALL; /* * Update the old var. The fbcon drivers still use this. * Once they are using cfb->fb.var, this can be dropped. * --rmk */ display->var = cfb->fb.var; /* * If we are setting all the virtual consoles, also set the * defaults used to create new consoles. */ if (var->activate & FB_ACTIVATE_ALL) cfb->fb.disp->var = cfb->fb.var; if (chgvar && info && cfb->fb.changevar) cfb->fb.changevar(con); fb_set_cmap(&cfb->fb.cmap, 1, s3c44b0fb_setcolreg, &cfb->fb); return 0;}/* * Get the currently displayed virtual consoles colormap. */static intgen_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info){ fb_copy_cmap(&info->cmap, cmap, kspc ? 0 : 2); return 0;}/* * Get the currently displayed virtual consoles fixed part of the display. */static intgen_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info){ *fix = info->fix; return 0;}/* * Get the current user defined part of the display. */static intgen_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info){ *var = info->var; return 0;}static struct fb_ops s3c44b0fb_ops = { owner: THIS_MODULE, fb_set_var: s3c44b0fb_set_var, fb_set_cmap: s3c44b0fb_set_cmap, fb_get_fix: gen_get_fix, fb_get_var: gen_get_var, fb_get_cmap: gen_get_cmap,};static int s3c44b0fb_updatevar(int con, struct fb_info *info){ return -EINVAL;}static void s3c44b0fb_blank(int blank, struct fb_info *info){ //TODO if (blank) { } else { }}/********************************************************************************/#define U8 __u8#define U16 __u16#define U32 __u32#define MAX749_CTRL 0x80#define MAX749_ADJ 0x40#define Max749AdjHi() outl(inl(S3C44B0X_PDATC)|MAX749_ADJ, S3C44B0X_PDATC)#define Max749AdjLo() outl(inl(S3C44B0X_PDATC)&~MAX749_ADJ, S3C44B0X_PDATC)#define Max749CtrlHi() outl(inl(S3C44B0X_PDATC)|MAX749_CTRL, S3C44B0X_PDATC)#define Max749CtrlLo() outl(inl(S3C44B0X_PDATC)&~MAX749_CTRL, S3C44B0X_PDATC)static void Max749Rst(void){ unsigned char i; Max749AdjHi(); Max749CtrlLo(); i = 100; while(i--); Max749CtrlHi();}static void Max749Up(U16 cnt){ unsigned char i; Max749Rst(); for(; cnt; cnt--) { Max749AdjLo(); i = 10; while(i--); Max749AdjHi(); i = 10; while(i--); }}//#define SCR_XSIZE 320//#define SCR_YSIZE 240//#define LCD_XSIZE 320//#define LCD_YSIZE 240#define SCR_XSIZE 240#define SCR_YSIZE 320#define LCD_XSIZE 240#define LCD_YSIZE 320#ifdef LCD_GRAY_16#define LCD_DEPTH 4#define LCD_BUF_SIZE ((SCR_XSIZE*SCR_YSIZE)>>1)#else#define LCD_DEPTH 8#define LCD_BUF_SIZE ((SCR_XSIZE*SCR_YSIZE))#endif///////////////////// LCDCON1#define CLKVAL (5<<12) //VCLK = MCLK/(2*CLKVAL)#define WLH (3<<10) //16 clock#define WDLY (3<<8) //16 clock#define MMODE (0<<7) //VM = ecah frame, not use MVAL#define DISMODE (1<<5) //4bit single scan#define INVCLK (0<<4) //falling edge fetch data#define INVLINE (0<<3) //normal, non inverse#define INVFRAME (0<<2) //normal#define INVVD (0<<1) //normal#define ENVID 1#define DSVID 0#define LCD_MODE_DS (CLKVAL|WLH|WDLY|MMODE|DISMODE|INVCLK|INVLINE|INVFRAME|INVVD|DSVID)#define LCD_MODE_EN (CLKVAL|WLH|WDLY|MMODE|DISMODE|INVCLK|INVLINE|INVFRAME|INVVD|ENVID)///////////////////// LCDCON2#define LINEBLINK 10///////////////////// LCDCON3#define SELFREF_EN 1#define SELFREF_DS 0///////////////////// LCDSADDR1#define MONO_MODE 0#define G4_MODE 1#define G16_MODE 2#define C8_MODE 3#define BankOfDisMem(addr) (((U32)(addr)>>22)<<21)#define BaseOfDisMem(addr) (((U32)(addr)>>1)&0x1fffff)///////////////////// LCDSADDR2#define BSWP_EN 1#define BSWP_DS 0//#define MVAL 13 --///////////////////// LCDSADDR3#define MONO_VS_SIZE (LCD_XSIZE/16)|(((SCR_XSIZE-LCD_XSIZE)/16)<<9)#define G4_VS_SIZE (LCD_XSIZE/8)|(((SCR_XSIZE-LCD_XSIZE)/8)<<9)#define G16_VS_SIZE (LCD_XSIZE/4)|(((SCR_XSIZE-LCD_XSIZE)/4)<<9)#define C8_VS_SIZE (LCD_XSIZE/2)|(((SCR_XSIZE-LCD_XSIZE)/2)<<9)//++#define M5D(n) ((n) )//& 0x1fffff)#define ARRAY_SIZE_MONO (SCR_XSIZE/8*SCR_YSIZE)#define ARRAY_SIZE_G4 (SCR_XSIZE/4*SCR_YSIZE)#define ARRAY_SIZE_G16 (SCR_XSIZE/2*SCR_YSIZE)#define ARRAY_SIZE_COLOR (SCR_XSIZE/1*SCR_YSIZE)#define HOZVAL (LCD_XSIZE/4-1)#define HOZVAL_COLOR (LCD_XSIZE*3/8-1)#define LINEVAL (LCD_YSIZE-1)#define MVAL (13)#define CLKVAL_MONO (6)#define CLKVAL_G4 (6)#define CLKVAL_G16 (6)#define CLKVAL_COLOR (6)#define MVAL_USED 0//++int __init s3c44b0xfb_init(void){ int err = -ENOMEM; char *fbuf; cfb = kmalloc(sizeof(*cfb) + sizeof(struct display), GFP_KERNEL); if (!cfb) goto out; memset(cfb, 0, sizeof(*cfb) + sizeof(struct display)); fbuf = kmalloc(LCD_BUF_SIZE, GFP_KERNEL); if(!fbuf){ kfree(cfb); goto out; } memset(fbuf, 0, LCD_BUF_SIZE); cfb->currcon = -1; strcpy(cfb->fb.fix.id, "s3c44b0"); cfb->fb.screen_base = fbuf; cfb->fb.fix.smem_start = fbuf; cfb->fb.fix.smem_len = LCD_BUF_SIZE; cfb->fb.fix.type = FB_TYPE_PACKED_PIXELS; cfb->fb.var.xres = LCD_XSIZE; cfb->fb.var.xres_virtual = SCR_XSIZE; cfb->fb.var.yres = LCD_YSIZE; cfb->fb.var.yres_virtual = SCR_YSIZE; cfb->fb.var.bits_per_pixel = LCD_DEPTH; cfb->fb.var.grayscale = 1; cfb->fb.var.activate = FB_ACTIVATE_NOW; cfb->fb.var.height = -1; cfb->fb.var.width = -1; //strcpy(cfb->fb.fontname,"FONT8x8"); cfb->fb.fbops = &s3c44b0fb_ops; cfb->fb.changevar = NULL;// cfb->fb.switch_con = s3c44b0fb_switch; cfb->fb.updatevar = s3c44b0fb_updatevar; cfb->fb.blank = s3c44b0fb_blank; cfb->fb.flags = FBINFO_FLAG_DEFAULT; cfb->fb.disp = (struct display *)(cfb + 1); fb_alloc_cmap(&cfb->fb.cmap, CMAP_SIZE, 0); /* * Power up the LCD */#ifdef LCD_GRAY_16 outw(0x0100,S3C44B0X_PDATC); //All IO is low, PC8 = 1 LCD-Off, PC9 = 0 BackLight Off outl(0xfff5ff54,S3C44B0X_PCONC); //0->D12SUSPD, 1~3->LED, 4~7->VD7~VD4, 8->DISPON, 9->BACKLIGHT, 10~13->UART1, 14->RTS0, 15->CTS0 outw(0x0000,S3C44B0X_PUPC);; //disable all pull-up //Max749Up(23); outl(0xaaaa, S3C44B0X_PCOND); //VFRAME,VM,VLINE,VCLK,VD3-VD0 enable outb(0x00,S3C44B0X_PUPD);/*SCR_XSIZE/4 outl(LCD_MODE_DS, S3C44B0X_LCDCON1); outl((LINEBLINK<<21)|(((LCD_XSIZE>>2)-1)<<10)|(LCD_YSIZE-1), S3C44B0X_LCDCON2); outl((G16_MODE<<27)|BankOfDisMem(fbuf)|BaseOfDisMem(fbuf), S3C44B0X_LCDSADDR1); outl((BSWP_EN<<29)|(MVAL<<21)|BaseOfDisMem((U32)fbuf+SCR_XSIZE*LCD_YSIZE/2), S3C44B0X_LCDSADDR2); outl(G16_VS_SIZE, S3C44B0X_LCDSADDR3); //outl(inl(S3C44B0X_PCONC)&~(0xf<<16), S3C44B0X_PCONC); //outl(inl(S3C44B0X_PCONC)|(5<<16), S3C44B0X_PCONC); //GPC8,9 output //for FS44B0 //outl(inl(S3C44B0X_PDATC)&~(3<<8), S3C44B0X_PDATC); //dis-on set GPC8 low// outl(inl(S3C44B0X_PDATC)|(1<<9), S3C44B0X_PDATC); //backlight on set GPC9 hi outl((inl(S3C44B0X_PCONE)&~(0xf<<6))|(5<<6), S3C44B0X_PCONE); outl((inl(S3C44B0X_PDATE)&~(0x3<<3))|(3<<3), S3C44B0X_PDATE);*/// outl(0x12210,S3C44B0X_DITHMODE); // outw(0xa5a5,S3C44B0X_DP1_2);// outl(0xba5da65,S3C44B0X_DP4_7);// outl(0xa5a5f,S3C44B0X_DP3_5);// outw(0xd6b,S3C44B0X_DP2_3);// outl(0xeb7b5ed,S3C44B0X_DP5_7);// outw(0x7dbe,S3C44B0X_DP3_4);// outl(0x7ebdf,S3C44B0X_DP4_5);// outl(0x7fdfbfe,S3C44B0X_DP6_7); //outl(LCD_MODE_DS, S3C44B0X_LCDCON1); outl((0)|(1<<1)|(1<<5)|(MVAL_USED<<7)|(0x3<<8)|(0x3<<10)|(CLKVAL_G16<<12),S3C44B0X_LCDCON1); // disable,4B_SNGL_SCAN,WDLY=8clk,WLH=8clk, outl((LINEVAL)|(HOZVAL<<10)|(10<<21),S3C44B0X_LCDCON2); //LINEBLANK=10 (without any calculation) outl((0x2<<27) | ( ((__u32)fbuf>>22)<<21 ) | M5D((__u32)fbuf>>1),S3C44B0X_LCDSADDR1); // 16-gray, LCDBANK, LCDBASEU outl(M5D((((__u32)fbuf+(SCR_XSIZE*SCR_YSIZE/2))>>1)) | (MVAL<<21),S3C44B0X_LCDSADDR2);// outl(M5D((((__u32)fbuf+(SCR_XSIZE/4*(SCR_YSIZE-1))))>>1) | (MVAL<<21),S3C44B0X_LCDSADDR2); // outl((SCR_XSIZE/4) | ( ((SCR_XSIZE-LCD_XSIZE)/4)<<9 ),S3C44B0X_LCDSADDR3);// outl((1)|(1<<1)|(1<<5)|(MVAL_USED<<7)|(0x3<<8)|(0x3<<10)|(CLKVAL_G16<<12),S3C44B0X_LCDCON1); //lcd disp_o outb(inb(S3C44B0X_PCONE) & (~(0xf<<6)) | (0x5<<6),S3C44B0X_PCONE) ; outb((inb(S3C44B0X_PDATE) | (3<<3) ),S3C44B0X_PDATE);#else //Max749Up(23); outl(inl(S3C44B0X_PCONC)&~0xff00, S3C44B0X_PCONC); outl(inl(S3C44B0X_PCONC)|0xff00, S3C44B0X_PCONC); //GPC4-GPC7 as VD7-VD4 outl(0xaaaa, S3C44B0X_PCOND); //VFRAME,VM,VLINE,VCLK,VD3-VD0 //outl(inl(S3C44B0X_PDATC)&~0x100, S3C44B0X_PDATC); // set GPC8 low outl((inl(S3C44B0X_PCONE)&~(0xf<<6))|(5<<6), S3C44B0X_PCONE); outl((inl(S3C44B0X_PDATE)&~(0x3<<3))|(3<<3), S3C44B0X_PDATE); outl((2<<5)|(3<<8)|(3<<10)|(8<<12), S3C44B0X_LCDCON1); outl((LINEBLINK<<21)|(((LCD_XSIZE*3/8)-1)<<10)|(LCD_YSIZE-1), S3C44B0X_LCDCON2); //outl((3<<27)|((int)fbuf>>1), S3C44B0X_LCDSADDR1); //outl(((((int)fbuf+LCD_XSIZE*LCD_YSIZE)>>1)&0x1fffff)|(13<<21)|(1<<29), S3C44B0X_LCDSADDR2); outl((C8_MODE<<27)|BankOfDisMem(fbuf)|BaseOfDisMem(fbuf), S3C44B0X_LCDSADDR1); outl((BSWP_EN<<29)|(MVAL<<21)|BaseOfDisMem((U32)fbuf+SCR_XSIZE*LCD_YSIZE), S3C44B0X_LCDSADDR2); outl(C8_VS_SIZE, S3C44B0X_LCDSADDR3); outl(0xfdb96420, S3C44B0X_REDLUT); outl(0xfdb96420, S3C44B0X_GREENLUT); outl(0xfb40, S3C44B0X_BLUELUT);#endif outl(inl(S3C44B0X_LCDCON1)|ENVID, S3C44B0X_LCDCON1); printk("LCD buffer : %p\n", fbuf);#ifndef LCD_GRAY_16 /*{ int idx = 0; //for(; idx<LCD_BUF_SIZE; idx++) // fbuf[idx] = 0x0; //while(1); for(; idx<LCD_BUF_SIZE/3; idx++) fbuf[idx] = 0xe0; for(; idx<(LCD_BUF_SIZE*2)/3; idx++) fbuf[idx] = 0x1c; for(; idx<LCD_BUF_SIZE; idx++) fbuf[idx] = 0x3; printk("%x\n", inl(S3C44B0X_LCDCON1)); printk("%x\n", inl(S3C44B0X_LCDCON2)); printk("%x\n", inl(S3C44B0X_LCDSADDR1)); printk("%x\n", inl(S3C44B0X_LCDSADDR2)); printk("%x\n", inl(S3C44B0X_LCDSADDR3)); while(1); }*/#endif s3c44b0fb_set_var(&cfb->fb.var, -1, &cfb->fb); err = register_framebuffer(&cfb->fb); printk("err=%d\n", err);out: return err;}static void __exit s3c44b0xfb_exit(void){ unregister_framebuffer(&cfb->fb); kfree(cfb);}int __init s3c44b0xfb_setup(char *options){ return 0;}#ifdef MODULEmodule_init(s3c44b0xfb_init);module_exit(s3c44b0xfb_exit);#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -