主机:VM - RedHat 9.0开发板:FL2440,linux-2.6.12arm-linux-gcc:3.4.1
- /*
- * linux/drivers/video/s3c2410fb.c
- */
-
- #include <linux/config.h>
- #include <linux/module.h>
- #include <linux/moduleparam.h>
- #include <linux/kernel.h>
- #include <linux/sched.h>
- #include <linux/errno.h>
- #include <linux/string.h>
- #include <linux/interrupt.h>
- #include <linux/slab.h>
- #include <linux/fb.h>
- #include <linux/delay.h>
- #include <linux/init.h>
- #include <linux/ioport.h>
- #include <linux/cpufreq.h>
- #include <linux/device.h>
- #include <linux/dma-mapping.h>
-
- #include <asm/hardware.h>
- #include <asm/io.h>
- #include <asm/irq.h>
- #include <asm/mach-types.h>
- #include <asm/uaccess.h>
- #include <asm/arch/regs-gpio.h>
- #include <asm/arch/regs-lcd.h>
- #include <asm/arch/regs-irq.h>
-
- #include "s3c2410fb.h"
-
- /*
- * Complain if VAR is out of range.
- */
- #define DEBUG_VAR 1
-
- // 通过写入一个数据到此寄存器来清除SRCPND 寄存器的指定位。其只清除那些数据中被设置为1 的相应
- // 位置的SRCPND 位。那些数据中被设置为0 的相应位置的位保持不变。
- #define ClearPending(x) {
- __raw_writel((1 << (x)), S3C2410_SRCPND);
- __raw_writel((1 << (x)), S3C2410_INTPND);
- }
-
- struct gzliu_fb_mach_info fs2410_info = {
- .pixclock = 270000,
- .xres = 320,
- .yres = 240,
- .bpp = 16,
- .hsync_len = 8,
- .left_margin = 5,
- .right_margin = 15,
- .vsync_len = 15,
- .upper_margin = 3,
- .lower_margin = 5,
- .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
- .cmap_greyscale = 0,
- .cmap_inverse = 0,
- .cmap_static = 0,
- .reg = {
- .lcdcon1 = (6<<8)|(0<<7)|(3<<5)|(12<<1),
- .lcdcon2 = (3<<24) | (239<<14) | (5<<6) | (15),
- .lcdcon3 = (58<<19) | (319<<8) | (15),
- .lcdcon4 = (13<<8) | (8),
- .lcdcon5 = (1<<11) | (0<<10) | (1<<9) | (1<<8) | (0<<7) | (0<<6) | (1<<3) |(0<<1) | (1),
- }
- };
-
- static void (*gzliu_fb_backlight_power)(int);
- static void (*gzliu_fb_lcd_power)(int);
-
- static int gzliu_fb_activate_var(struct fb_var_screeninfo *var, struct gzliu_fb_info *);
- static void set_ctrlr_state(struct gzliu_fb_info *fbi, u_int state);
-
- static inline void gzliu_fb_schedule_work(struct gzliu_fb_info *fbi, u_int state)
- {
- printk("@@@@@@@@@@ gzliu_fb_schedule_work() @@@@@@@@@@@@
");
- unsigned long flags;
-
- local_irq_save(flags);
- /*
- * We need to handle two requests being made at the same time.
- * There are two important cases:
- * 1. When we are changing VT (C_REENABLE) while unblanking (C_ENABLE)
- * We must perform the unblanking, which will do our REENABLE for us.
- * 2. When we are blanking, but immediately unblank before we have
- * blanked. We do the "REENABLE" thing here as well, just to be sure.
- */
- if (fbi->task_state == C_ENABLE && state == C_REENABLE)
- state = (u_int) -1;
- if (fbi->task_state == C_DISABLE && state == C_ENABLE)
- state = C_REENABLE;
-
- if (state != (u_int)-1) {
- fbi->task_state = state;
- schedule_work(&fbi->task);
- }
- local_irq_restore(flags);
- }
-
- static inline u_int chan_to_field(u_int chan, struct fb_bitfield *bf)
- {
- printk("@@@@@@@@@@ chan_to_field() @@@@@@@@@@@@
");
- chan &= 0xffff;
- chan >>= 16 - bf->length;
- return chan << bf->offset;
- }
-
- static int gzliu_fb_setpalettereg(u_int regno, u_int red, u_int green, u_int blue,
- u_int trans, struct fb_info *info)
- {
- printk("@@@@@@@@@@ gzliu_fb_setpalettereg() @@@@@@@@@@@@
");
- struct gzliu_fb_info *fbi = (struct gzliu_fb_info *)info;
- u_int val, ret = 1;
-
- if (regno < fbi->palette_size) {
- if (fbi->fb.var.grayscale) {
- val = ((blue >> 8) & 0x00ff);
- } else {
- val = ((red >> 0) & 0xf800);
- val |= ((green >> 5) & 0x07e0);
- val |= ((blue >> 11) & 0x001f);
- }
-
- fbi->palette_cpu[regno] = val;
- ret = 0;
- }
- return ret;
- }
-
- static int gzliu_fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
- u_int trans, struct fb_info *info)
- {
- printk("@@@@@@@@@@ gzliu_fb_setcolreg() @@@@@@@@@@@@
");
- struct gzliu_fb_info *fbi = (struct gzliu_fb_info *)info;
- unsigned int val;
- int ret = 1;
-
- /*
- * If inverse mode was selected, invert all the colours
- * rather than the register number. The register number
- * is what you poke into the framebuffer to produce the
- * colour you requested.
- */
- if (fbi->cmap_inverse) {
- red = 0xffff - red;
- green = 0xffff - green;
- blue = 0xffff - blue;
- }
-
- /*
- * If greyscale is true, then we convert the RGB value
- * to greyscale no matter what visual we are using.
- */
- if (fbi->fb.var.grayscale)
- red = green = blue = (19595 * red + 38470 * green +
- 7471 * blue) >> 16;
-
- switch (fbi->fb.fix.visual) {
- case FB_VISUAL_TRUECOLOR:
- /*
- * 12 or 16-bit True Colour. We encode the RGB value
- * according to the RGB bitfield information.
- */
- if (regno < 16) {
- u32 *pal = fbi->fb.pseudo_palette;
-
- val = chan_to_field(red, &fbi->fb.var.red);
- val |= chan_to_field(green, &fbi->fb.var.green);
- val |= chan_to_field(blue, &fbi->fb.var.blue);
-
- pal[regno] = val;
- ret = 0;
- }
- break;
-
- case FB_VISUAL_STATIC_PSEUDOCOLOR:
- case FB_VISUAL_PSEUDOCOLOR:
- ret = gzliu_fb_setpalettereg(regno, red, green, blue, trans, info);
- break;
- }
-
- return ret;
- }
-
- /*
- * gzliu_fb_check_var():
- * Get the video params out of "var". If a value doesn"t fit, round it up,
- * if it"s too big, return -EINVAL.
- *
- * Round up in the following order: bits_per_pixel, xres,
- * yres, xres_virtual, yres_virtual, xoffset, yoffset, grayscale,
- * bitfields, horizontal timing, vertical timing.
- */
- static int gzliu_fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
- {
- printk("@@@@@@@@@@ gzliu_fb_check_var() @@@@@@@@@@@@
");
- struct gzliu_fb_info *fbi = (struct gzliu_fb_info *)info;
-
- if (var->xres < MIN_XRES)
- var->xres = MIN_XRES;
- if (var->yres < MIN_YRES)
- var->yres = MIN_YRES;
- if (var->xres > fbi->max_xres)
- var->xres = fbi->max_xres;
- if (var->yres > fbi->max_yres)
- var->yres = fbi->max_yres;
- var->xres_virtual =
- max(var->xres_virtual, var->xres);
- var->yres_virtual =
- max(var->yres_virtual, var->yres);
-
- /*
- * Setup the RGB parameters for this display.
- *
- * The pixel packing format is described on page 7-11 of the
- * PXA2XX Developer"s Manual.
- */
- if ( var->bits_per_pixel == 16 ) {
- var->red.offset = 11; var->red.length = 5;
- var->green.offset = 5; var->green.length = 6;
- var->blue.offset = 0; var->blue.length = 5;
- var->transp.offset = var->transp.length = 0;
- } else {
- var->red.offset = var->green.offset = var->blue.offset = var->transp.offset = 0;
- var->red.length = 8;
- var->green.length = 8;
- var->blue.length = 8;
- var->transp.length = 0;
- }
-
- #ifdef CONFIG_CPU_FREQ
- DPRINTK("dma period = %d ps, clock = %d kHz
",
- gzliu_fb_display_dma_period(var),
- get_clk_frequency_khz(0));
- #endif
-
- return 0;
- }
-
- static inline void gzliu_fb_set_truecolor(u_int is_true_color)
- {
- printk("@@@@@@@@@@ gzliu_fb_set_truecolor() @@@@@@@@@@@@
");
- DPRINTK("true_color = %d
", is_true_color);
- }
-
- /*
- * gzliu_fb_set_par():
- * Set the user defined part of the display for the specified console
- */
- static int gzliu_fb_set_par(struct fb_info *info)
- {
- printk("@@@@@@@@@@ gzliu_fb_set_par() @@@@@@@@@@@@
");
- struct gzliu_fb_info *fbi = (struct gzliu_fb_info *)info;
- struct fb_var_screeninfo *var = &info->var;
- unsigned long palette_mem_size;
-
- DPRINTK("set_par
");
-
- if (var->bits_per_pixel == 16)
- fbi->fb.fix.visual = FB_VISUAL_TRUECOLOR;
- else if (!fbi->cmap_static)
- fbi->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR;
- else {
- /*
- * Some people have weird ideas about wanting static
- * pseudocolor maps. I suspect their user space
- * applications are broken.
- */
- fbi->fb.fix.visual = FB_VISUAL_STATIC_PSEUDOCOLOR;
- }
-
- fbi->fb.fix.line_length = var->xres_virtual *
- var->bits_per_pixel / 8;
- if (var->bits_per_pixel == 16)
- fbi->palette_size = 0;
- else
- fbi->palette_size = var->bits_per_pixel == 1 ? 4 : 1 << var->bits_per_pixel;
-
- palette_mem_size = fbi->palette_size * sizeof(u16);
-
- printk("@@@@@@@ palette_mem_size = 0x%08lx
", (u_long) palette_mem_size);
-
- fbi->palette_cpu = (u16 *)(fbi->map_cpu + PAGE_SIZE - palette_mem_size);
- fbi->palette_dma = fbi->map_dma + PAGE_SIZE - palette_mem_size;
-
- /*
- * Set (any) board control register to handle new color depth
- */
- gzliu_fb_set_truecolor(fbi->fb.fix.visual == FB_VISUAL_TRUECOLOR);
-
- if (fbi->fb.var.bits_per_pixel == 16)
- fb_dealloc_cmap(&fbi->fb.cmap);
- else
- fb_alloc_cmap(&fbi->fb.cmap, 1<<fbi->fb.var.bits_per_pixel, 0);
-
- gzliu_fb_activate_var(var, fbi);
-
- return 0;
- }
-
- /*
- * gzliu_fb_blank():
- * Blank the display by setting all palette values to zero. Note, the
- * 12 and 16 bpp modes don"t really use the palette, so this will not
- * blank the display in all modes.
- */
- static int gzliu_fb_blank(int blank, struct fb_info *info)
- {
- printk("@@@@@@@@@@ gzliu_fb_blank() @@@@@@@@@@@@
");
- struct gzliu_fb_info *fbi = (struct gzliu_fb_info *)info;
- int i;
-
- DPRINTK("gzliu_fb_blank: blank=%d
", blank);
-
- switch (blank) {
- case VESA_POWERDOWN:
- case VESA_VSYNC_SUSPEND:
- case VESA_HSYNC_SUSPEND:
- if (fbi->fb.fix.visual == FB_VISUAL_PSEUDOCOLOR ||
- fbi->fb.fix.visual == FB_VISUAL_STATIC_PSEUDOCOLOR)
- for (i = 0; i < fbi->palette_size; i++);
-
- gzliu_fb_schedule_work(fbi, C_DISABLE);
- break;
-
- case VESA_NO_BLANKING:
- if (fbi->fb.fix.visual == FB_VISUAL_PSEUDOCOLOR ||
- fbi->fb.fix.visual == FB_VISUAL_STATIC_PSEUDOCOLOR)
- fb_set_cmap(&fbi->fb.cmap, info);
- gzliu_fb_schedule_work(fbi, C_ENABLE);
- }
- return 0;
- }
-
- static int soft_cursor_dummy(struct fb_info *info, struct fb_cursor *cursor)
- {
- printk("@@@@@@@@@@ soft_cursor_dummy() @@@@@@@@@@@@
");
- return 0;
- }
-
- static struct fb_ops gzliu_fb_ops = {
- .owner = THIS_MODULE,
- .fb_check_var = gzliu_fb_check_var,
- .fb_set_par = gzliu_fb_set_par,
- .fb_setcolreg = gzliu_fb_setcolreg,
- .fb_blank = gzliu_fb_blank,
- .fb_cursor = soft_cursor_dummy,
- };
-
- static inline unsigned int get_pcd(unsigned int pixclock)
- {
- printk("@@@@@@@@@@ get_pcd() @@@@@@@@@@@@
");
- unsigned long long pcd;
-
- pcd = s3c2410_hclk/(((__raw_readl(S3C2410_LCDCON1)>>8)&0x3ff)*2+1);
- return (unsigned int)pcd;
- }
-
- /*
- * gzliu_fb_activate_var():
- * Configures LCD Controller based on entries in var parameter. Settings are
- * only written to the controller if changes were made.
- */
- static int gzliu_fb_activate_var(struct fb_var_screeninfo *var, struct gzliu_fb_info *fbi)
- {
- printk("@@@@@@@@@@ gzliu_fb_activate_var() @@@@@@@@@@@@
");
- struct gzliu_fb_lcd_reg new_regs;
- u_long flags;
- u_int half_screen_size, yres;
- unsigned long VideoPhysicalTemp = fbi->screen_dma;
-
- DPRINTK("Configuring gzliu_ LCD
");
-
- DPRINTK("var: xres=%d hslen=%d lm=%d rm=%d
",
- var->xres, var->hsync_len,
- var->left_margin, var->right_margin);
- DPRINTK("var: yres=%d vslen=%d um=%d bm=%d
",
- var->yres, var->vsync_len,
- var->upper_margin, var->lower_margin);
- DPRINTK("var: pixclock=%d pcd=%d
", var->pixclock, pcd);
-
- #if DEBUG_VAR
- if (var->xres < 16 || var->xres > 1024)
- printk(KERN_ERR "%s: invalid xres %d
",
- fbi->fb.fix.id, var->xres);
- switch(var->bits_per_pixel) {
- case 1:
- case 2:
- case 4:
- case 8:
- case 16:
- break;
- default:
- printk(KERN_ERR "%s: invalid bit depth %d
",
- fbi->fb.fix.id, var->bits_per_pixel);
- break;
- }
- if (var->hsync_len < 1 || var->hsync_len > 64)
- printk(KERN_ERR "%s: invalid hsync_len %d
",
- fbi->fb.fix.id, var->hsync_len);
- if (var->left_margin < 1 || var->left_margin > 255)
- printk(KERN_ERR "%s: invalid left_margin %d
",
- fbi->fb.fix.id, var->left_margin);
- if (var->right_margin < 1 || var->right_margin > 255)
- printk(KERN_ERR "%s: invalid right_margin %d
",
- fbi->fb.fix.id, var->right_margin);
- if (var->yres < 1 || var->yres > 1024)
- printk(KERN_ERR "%s: invalid yres %d
",
- fbi->fb.fix.id, var->yres);
- if (var->vsync_len < 1 || var->vsync_len > 64)
- printk(KERN_ERR "%s: invalid vsync_len %d
",
- fbi->fb.fix.id, var->vsync_len);
- if (var->upper_margin < 0 || var->upper_margin > 255)
- printk(KERN_ERR "%s: invalid upper_margin %d
",
- fbi->fb.fix.id, var->upper_margin);
- if (var->lower_margin < 0 || var->lower_margin > 255)
- printk(KERN_ERR "%s: invalid lower_margin %d
",
- fbi->fb.fix.id, var->lower_margin);
- #endif
-
- /* Update shadow copy atomically */
- local_irq_save(flags);
-
- new_regs.lcdcon1 = fbi->reg.lcdcon1 & ~S3C2410_LCDCON1_ENVID;
-
- new_regs.lcdcon2 = (fbi->reg.lcdcon2 & ~LCD2_LINEVAL_MSK)
- | LCD2_LINEVAL(var->yres - 1);
-
- /* TFT LCD only ! */
- new_regs.lcdcon3 = (fbi->reg.lcdcon3 & ~LCD3_HOZVAL_MSK)
- | LCD3_HOZVAL(var->xres - 1);
-
- new_regs.lcdcon4 = fbi->reg.lcdcon4;
- new_regs.lcdcon5 = fbi->reg.lcdcon5;
-
- new_regs.lcdsaddr1 =
- LCDADDR_BANK(((unsigned long)VideoPhysicalTemp >> 22))
- | LCDADDR_BASEU(((unsigned long)VideoPhysicalTemp >> 1));
-
- /* 16bpp */
- new_regs.lcdsaddr2 = LCDADDR_BASEL(
- ((unsigned long)VideoPhysicalTemp + (var->xres * 2 * (var->yres/*-1*/)))
- >> 1);
-
- new_regs.lcdsaddr3 = LCDADDR_OFFSET(0) | (LCDADDR_PAGE(var->xres) /*>> 1*/);
-
- yres = var->yres;
-
- half_screen_size = var->bits_per_pixel;
- half_screen_size = half_screen_size * var->xres * var->yres / 16;
-
- fbi->reg.lcdcon1 = new_regs.lcdcon1;
- fbi->reg.lcdcon2 = new_regs.lcdcon2;
- fbi->reg.lcdcon3 = new_regs.lcdcon3;
- fbi->reg.lcdcon4 = new_regs.lcdcon4;
- fbi->reg.lcdcon5 = new_regs.lcdcon5;
- fbi->reg.lcdsaddr1 = new_regs.lcdsaddr1;
- fbi->reg.lcdsaddr2 = new_regs.lcdsaddr2;
- fbi->reg.lcdsaddr3 = new_regs.lcdsaddr3;
-
- __raw_writel(fbi->reg.lcdcon1&~S3C2410_LCDCON1_ENVID, S3C2410_LCDCON1);
- __raw_writel(fbi->reg.lcdcon2, S3C2410_LCDCON2);
- __raw_writel(fbi->reg.lcdcon3, S3C2410_LCDCON3);
- __raw_writel(fbi->reg.lcdcon4, S3C2410_LCDCON4);
- __raw_writel(fbi->reg.lcdcon5, S3C2410_LCDCON5);
- __raw_writel(fbi->reg.lcdsaddr1, S3C2410_LCDSADDR1);
- __raw_writel(fbi->reg.lcdsaddr2, S3C2410_LCDSADDR2);
- __raw_writel(fbi->reg.lcdsaddr3, S3C2410_LCDSADDR3);
-
- //next code should not be used in TX06D18 LCD
- #if !defined (TX06D18_TFT_LCD ) //change by gongjun
- #if defined(CONFIG_S3C2410_SMDK) && !defined(CONFIG_SMDK_AIJI)
- LCDLPCSEL = 0x2;
- #elif defined(CONFIG_S3C2410_SMDK) && defined(CONFIG_SMDK_AIJI)
- LCDLPCSEL = 0x7;
- #endif
- #endif
-
- __raw_writel(0, S3C2410_TPAL);
- __raw_writel(fbi->reg.lcdcon1|S3C2410_LCDCON1_ENVID, S3C2410_LCDCON1);
-
- #if 1
- {
- printk("LCDCON1 0x%08x
", __raw_readl(S3C2410_LCDCON1));
- printk("LCDCON2 0x%08x
", __raw_readl(S3C2410_LCDCON2));
- printk("LCDCON3 0x%08x
", __raw_readl(S3C2410_LCDCON3));
- printk("LCDCON4 0x%08x
", __raw_readl(S3C2410_LCDCON4));
- printk("LCDCON5 0x%08x
", __raw_readl(S3C2410_LCDCON5));
- printk("LCDSADDR1 0x%08x
", __raw_readl(S3C2410_LCDSADDR1));
- printk("LCDSADDR2 0x%08x
", __raw_readl(S3C2410_LCDSADDR2));
- printk("LCDSADDR3 0x%08x
", __raw_readl(S3C2410_LCDSADDR3));
- }
- #endif
- local_irq_restore(flags);
-
- return 0;
- }
-
- /*
- * NOTE! The following functions are purely helpers for set_ctrlr_state.
- * Do not call them directly; set_ctrlr_state does the correct serialisation
- * to ensure that things happen in the right way 100% of time time.
- * -- rmk
- */
- static inline void __gzliu_fb_backlight_power(struct gzliu_fb_info *fbi, int on)
- {
- printk("@@@@@@@@@@ __gzliu_fb_backlight_power() @@@@@@@@@@@@
");
- printk("backlight o%s
", on ? "n" : "ff");
-
- if (gzliu_fb_backlight_power)
- gzliu_fb_backlight_power(on);
- }
-
- static inline void __gzliu_fb_lcd_power(struct gzliu_fb_info *fbi, int on)
- {
- printk("@@@@@@@@@@ __gzliu_fb_lcd_power() @@@@@@@@@@@@
");
- printk("LCD power o%s
", on ? "n" : "ff");
-
- if (gzliu_fb_lcd_power)
- gzliu_fb_lcd_power(on);
- }
-
- static void gzliu_fb_setup_gpio(struct gzliu_fb_info *fbi)
- {
- printk("@@@@@@@@@@ gzliu_fb_setup_gpio() @@@@@@@@@@@@
");
- DPRINTK("setup gpio
");
-
- // 将GPD这组GPIO的16个引脚配置为VD
- __raw_writel(0xaaaaaaaa, S3C2410_GPDCON);
- __raw_writel(7, S3C2410_LCDINTMSK); // 3 by gjl MASK LCD Sub Interrupt
- __raw_writel(0, S3C2410_TPAL); // Disable Temp Palette
- __raw_writel(0, S3C2410_LPCSEL); // 0 by gjl Disable LPC3600
- __raw_writel(0, S3C2410_PRIORITY); //0x7f add by gjl
- }
-
- static void gzliu_fb_enable_controller(struct gzliu_fb_info *fbi)
- {
- printk("@@@@@@@@@@ gzliu_fb_enable_controller() @@@@@@@@@@@@
");
- __raw_writel(fbi->reg.lcdcon1&~S3C2410_LCDCON1_ENVID, S3C2410_LCDCON1);
- __raw_writel(fbi->reg.lcdcon2, S3C2410_LCDCON2);
- __raw_writel(fbi->reg.lcdcon3, S3C2410_LCDCON3);
- __raw_writel(fbi->reg.lcdcon4, S3C2410_LCDCON4);
- __raw_writel(fbi->reg.lcdcon5, S3C2410_LCDCON5);
- __raw_writel(fbi->reg.lcdsaddr1, S3C2410_LCDSADDR1);
- __raw_writel(fbi->reg.lcdsaddr2, S3C2410_LCDSAD