Linux S3C2440 LCD 设备驱动
Linux S3C2440 LCD 设备驱动
主机:VM - RedHat 9.0
开发板:FL2440,linux-2.6.12
arm-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() @@@@@@@@@@@@\n");
- 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() @@@@@@@@@@@@\n");
- 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() @@@@@@@@@@@@\n");
- 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() @@@@@@@@@@@@\n");
- 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() @@@@@@@@@@@@\n");
- 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\n",
- 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() @@@@@@@@@@@@\n");
- DPRINTK("true_color = %d\n", 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() @@@@@@@@@@@@\n");
- 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\n");
- 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\n", (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() @@@@@@@@@@@@\n");
- struct gzliu_fb_info *fbi = (struct gzliu_fb_info *)info;
- int i;
- DPRINTK("gzliu_fb_blank: blank=%d\n", 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() @@@@@@@@@@@@\n");
- 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() @@@@@@@@@@@@\n");
- 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() @@@@@@@@@@@@\n");
- 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\n");
- DPRINTK("var: xres=%d hslen=%d lm=%d rm=%d\n",
- var->xres, var->hsync_len,
- var->left_margin, var->right_margin);
- DPRINTK("var: yres=%d vslen=%d um=%d bm=%d\n",
- var->yres, var->vsync_len,
- var->upper_margin, var->lower_margin);
- DPRINTK("var: pixclock=%d pcd=%d\n", var->pixclock, pcd);
- #if DEBUG_VAR
- if (var->xres < 16 || var->xres > 1024)
- printk(KERN_ERR "%s: invalid xres %d\n",
- 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\n",
- 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\n",
- fbi->fb.fix.id, var->hsync_len);
- if (var->left_margin < 1 || var->left_margin > 255)
- printk(KERN_ERR "%s: invalid left_margin %d\n",
- fbi->fb.fix.id, var->left_margin);
- if (var->right_margin < 1 || var->right_margin > 255)
- printk(KERN_ERR "%s: invalid right_margin %d\n",
- fbi->fb.fix.id, var->right_margin);
- if (var->yres < 1 || var->yres > 1024)
- printk(KERN_ERR "%s: invalid yres %d\n",
- fbi->fb.fix.id, var->yres);
- if (var->vsync_len < 1 || var->vsync_len > 64)
- printk(KERN_ERR "%s: invalid vsync_len %d\n",
- fbi->fb.fix.id, var->vsync_len);
- if (var->upper_margin < 0 || var->upper_margin > 255)
- printk(KERN_ERR "%s: invalid upper_margin %d\n",
- fbi->fb.fix.id, var->upper_margin);
- if (var->lower_margin < 0 || var->lower_margin > 255)
- printk(KERN_ERR "%s: invalid lower_margin %d\n",
- 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\n", __raw_readl(S3C2410_LCDCON1));
- printk("LCDCON2 0x%08x\n", __raw_readl(S3C2410_LCDCON2));
- printk("LCDCON3 0x%08x\n", __raw_readl(S3C2410_LCDCON3));
- printk("LCDCON4 0x%08x\n", __raw_readl(S3C2410_LCDCON4));
- printk("LCDCON5 0x%08x\n", __raw_readl(S3C2410_LCDCON5));
- printk("LCDSADDR1 0x%08x\n", __raw_readl(S3C2410_LCDSADDR1));
- printk("LCDSADDR2 0x%08x\n", __raw_readl(S3C2410_LCDSADDR2));
- printk("LCDSADDR3 0x%08x\n", __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() @@@@@@@@@@@@\n");
- printk("backlight o%s\n", 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() @@@@@@@@@@@@\n");
- printk("LCD power o%s\n", 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() @@@@@@@@@@@@\n");
- DPRINTK("setup gpio\n");
- // 将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() @@@@@@@@@@@@\n");
- __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);
- __raw_writel(fbi->reg.lcdcon1|S3C2410_LCDCON1_ENVID, S3C2410_LCDCON1);
- #if 1
- printk("LCDCON1 0x%08x\n", __raw_readl(S3C2410_LCDCON1));
- printk("LCDCON2 0x%08x\n", __raw_readl(S3C2410_LCDCON2));
- printk("LCDCON3 0x%08x\n", __raw_readl(S3C2410_LCDCON3));
- printk("LCDCON4 0x%08x\n", __raw_readl(S3C2410_LCDCON4));
- printk("LCDCON5 0x%08x\n", __raw_readl(S3C2410_LCDCON5));
- printk("LCDSADDR1 0x%08x\n", __raw_readl(S3C2410_LCDSADDR1));
- printk("LCDSADDR2 0x%08x\n", __raw_readl(S3C2410_LCDSADDR2));
- printk("LCDSADDR3 0x%08x\n", __raw_readl(S3C2410_LCDSADDR3));
- #endif
- }
- static void gzliu_fb_disable_controller(struct gzliu_fb_info *fbi)
- {
- printk("@@@@@@@@@@ gzliu_fb_disable_controller() @@@@@@@@@@@@\n");
- __raw_writel(fbi->reg.lcdcon1&~S3C2410_LCDCON1_ENVID, S3C2410_LCDCON1);
- }
- /*
- * This function must be called from task context only, since it will
- * sleep when disabling the LCD controller, or if we get two contending
- * processes trying to alter state.
- */
- static void set_ctrlr_state(struct gzliu_fb_info *fbi, u_int state)
- {
- printk("@@@@@@@@@@ set_ctrlr_state() @@@@@@@@@@@@\n");
- u_int old_state;
- down(&fbi->ctrlr_sem);
- old_state = fbi->state;
- /*
- * Hack around fbcon initialisation.
- */
- if (old_state == C_STARTUP && state == C_REENABLE)
- state = C_ENABLE;
- switch (state) {
- case C_DISABLE_CLKCHANGE:
- /*
- * Disable controller for clock change. If the
- * controller is already disabled, then do nothing.
- */
- if (old_state != C_DISABLE && old_state != C_DISABLE_PM) {
- fbi->state = state;
- gzliu_fb_disable_controller(fbi);
- }
- break;
- case C_DISABLE_PM:
- case C_DISABLE:
- /*
- * Disable controller
- */
- if (old_state != C_DISABLE) {
- fbi->state = state;
- __gzliu_fb_backlight_power(fbi, 0);
- __gzliu_fb_lcd_power(fbi, 0);
- if (old_state != C_DISABLE_CLKCHANGE)
- gzliu_fb_disable_controller(fbi);
- }
- break;
- case C_ENABLE_CLKCHANGE:
- /*
- * Enable the controller after clock change. Only
- * do this if we were disabled for the clock change.
- */
- if (old_state == C_DISABLE_CLKCHANGE) {
- fbi->state = C_ENABLE;
- gzliu_fb_enable_controller(fbi);
- }
- break;
- case C_REENABLE:
- /*
- * Re-enable the controller only if it was already
- * enabled. This is so we reprogram the control
- * registers.
- */
- if (old_state == C_ENABLE) {
- gzliu_fb_disable_controller(fbi);
- gzliu_fb_setup_gpio(fbi);
- gzliu_fb_enable_controller(fbi);
- }
- break;
- case C_ENABLE_PM:
- /*
- * Re-enable the controller after PM. This is not
- * perfect - think about the case where we were doing
- * a clock change, and we suspended half-way through.
- */
- if (old_state != C_DISABLE_PM)
- break;
- /* fall through */
- case C_ENABLE:
- /*
- * Power up the LCD screen, enable controller, and
- * turn on the backlight.
- */
- if (old_state != C_ENABLE) {
- fbi->state = C_ENABLE;
- gzliu_fb_setup_gpio(fbi);
- gzliu_fb_enable_controller(fbi);
- __gzliu_fb_lcd_power(fbi, 1);
- __gzliu_fb_backlight_power(fbi, 1);
- }
- break;
- }
- up(&fbi->ctrlr_sem);
- }/* static void set_ctrlr_state() */
- /*
- * Our LCD controller task (which is called when we blank or unblank)
- * via keventd.
- */
- static void gzliu_fb_task(void *dummy)
- {
- printk("@@@@@@@@@@ gzliu_fb_task() @@@@@@@@@@@@\n");
- struct gzliu_fb_info *fbi = dummy;
- u_int state = xchg(&fbi->task_state, -1);
- set_ctrlr_state(fbi, state);
- }
- void *consistent_alloc(int gfp, size_t size, dma_addr_t *dma_handle)
- {
- printk("@@@@@@@@@@ consistent_alloc() @@@@@@@@@@@@\n");
- struct page *page, *end, *free;
- unsigned long order;
- void *ret, *virt;
- if (in_interrupt())
- BUG();
- /*
- * // PAGE_SHIFT determines the page size //
- *
- * #define PAGE_SHIFT 12
- * #define PAGE_SIZE (1UL << PAGE_SHIFT)
- * #define PAGE_MASK (~(PAGE_SIZE-1))
- *
- * // to align the pointer to the (next) page boundary //
- *
- * #define PAGE_ALIGN(addr) (((addr)+PAGE_SIZE-1)&PAGE_MASK)
- */
- size = PAGE_ALIGN(size);
- /*
- * include/asm-arm/page.h
- *
- * // Pure 2^n version of get_order //
- * static inline int get_order(unsigned long size)
- * {
- * int order;
- *
- * size = (size-1) >> (PAGE_SHIFT-1);
- * order = -1;
- * do {
- * size >>= 1;
- * order++;
- * } while (size);
- * return order;
- * }
- */
- order = get_order(size);
- page = alloc_pages(gfp, order);
- if (!page)
- goto no_page;
- /*
- * We could do with a page_to_phys and page_to_bus here.
- */
- virt = page_address(page);
- /*
- * #define __virt_to_phys(x) ((x) - PAGE_OFFSET + PHYS_OFFSET)
- * #define __phys_to_virt(x) ((x) - PHYS_OFFSET + PAGE_OFFSET)
- *
- * dma_handle -- 物理地址
- * ret -- 映射后的虚拟地址
- */
- *dma_handle = virt_to_bus(virt);
- ret = __ioremap(virt_to_phys(virt), size, 0,0);
- if (!ret)
- goto no_remap;
- #if 0 /* ioremap_does_flush_cache_all */
- /*
- * we need to ensure that there are no cachelines in use, or
- * worse dirty in this area. Really, we don't need to do
- * this since __ioremap does a flush_cache_all() anyway. --rmk
- */
- invalidate_dcache_range(virt, virt + size);
- #endif
- /*
- * free wasted pages. We skip the first page since we know
- * that it will have count = 1 and won't require freeing.
- * We also mark the pages in use as reserved so that
- * remap_page_range works.
- */
- page = virt_to_page(virt);
- free = page + (size >> PAGE_SHIFT);
- end = page + (1 << order);
- for (; page < end; page++) {
- set_page_count(page, 1);
- if (page >= free)
- __free_page(page);
- else
- SetPageReserved(page);
- }
- return ret;
- no_remap:
- __free_pages(page, order);
- no_page:
- return NULL;
- }
- /*
- * gzliu_fb_map_video_memory():
- * Allocates the DRAM memory for the frame buffer. This buffer is
- * remapped into a non-cached, non-buffered, memory region to
- * allow palette and pixel writes to occur without flushing the
- * cache. Once this area is remapped, all virtual memory
- * access to the video memory should occur at the new region.
- */
- static int __init gzliu_fb_map_video_memory(struct gzliu_fb_info *fbi)
- {
- printk("@@@@@@@@@@ gzliu_fb_map_video_memory() @@@@@@@@@@@@\n");
- u_long palette_mem_size;
- /*
- * We reserve one page for the palette, plus the size
- * of the framebuffer.
- */
- fbi->map_size = PAGE_ALIGN(fbi->fb.fix.smem_len + PAGE_SIZE);
- //changed by gjl dma_alloc_writecombine dma_alloc_coherent
- fbi->map_cpu = consistent_alloc(GFP_KERNEL, fbi->map_size,
- &fbi->map_dma); //fbi->dev, fbi->map_size,&fbi->map_dma, GFP_KERNEL);
- if (fbi->map_cpu) {
- printk("@@@@@@ VA=0x%p, PA=0x%08x, size=0x%08x\n", fbi->map_cpu, fbi->map_dma, fbi->map_size);
- /* prevent initial garbage on screen */
- memset(fbi->map_cpu, 0, fbi->map_size);
- fbi->fb.screen_base = fbi->map_cpu + PAGE_SIZE;
- fbi->screen_dma = fbi->map_dma + PAGE_SIZE;
- /*
- * FIXME: this is actually the wrong thing to place in
- * smem_start. But fbdev suffers from the problem that
- * it needs an API which doesn't exist (in this case,
- * dma_writecombine_mmap)
- */
- fbi->fb.fix.smem_start = fbi->screen_dma;
- fbi->palette_size = fbi->fb.var.bits_per_pixel == 8 ? 256 : 16;
- palette_mem_size = fbi->palette_size * sizeof(u16);
- printk("@@@@@@@ palette_mem_size = 0x%08lx\n", (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;
- }
- return fbi->map_cpu ? 0 : -ENOMEM;
- }
- static struct gzliu_fb_info * __init gzliu_fb_init_fbinfo(struct device *dev)
- {
- printk("@@@@@@@@@@ gzliu_fb_init_fbinfo() @@@@@@@@@@@@\n");
- struct gzliu_fb_info *fbi;
- void *addr;
- struct gzliu_fb_mach_info *inf = &fs2410_info;//dev->platform_data;
- /* Alloc the gzliu_fb_info and pseudo_palette in one step */
- fbi = kmalloc(sizeof(struct gzliu_fb_info) + sizeof(u32) * 16, GFP_KERNEL);
- if (!fbi)
- return NULL;
- memset(fbi, 0, sizeof(struct gzliu_fb_info));
- fbi->dev = dev;
- strcpy(fbi->fb.fix.id, GZLIU_NAME);
- fbi->fb.fix.type = FB_TYPE_PACKED_PIXELS;
- fbi->fb.fix.type_aux = 0;
- fbi->fb.fix.xpanstep = 0;
- fbi->fb.fix.ypanstep = 0;
- fbi->fb.fix.ywrapstep = 0;
- fbi->fb.fix.accel = FB_ACCEL_NONE; // 没有硬件加速
- fbi->fb.var.nonstd = 0;
- fbi->fb.var.activate = FB_ACTIVATE_NOW;
- fbi->fb.var.height = -1;
- fbi->fb.var.width = -1;
- fbi->fb.var.accel_flags = 0;
- fbi->fb.var.vmode = FB_VMODE_NONINTERLACED;
- fbi->fb.fbops = &gzliu_fb_ops;
- fbi->fb.flags = FBINFO_FLAG_DEFAULT;
- fbi->fb.node = -1;
- fbi->fb.currcon = -1;
- addr = fbi;
- addr = addr + sizeof(struct gzliu_fb_info);
- fbi->fb.pseudo_palette = addr;
- fbi->max_xres = inf->xres;
- fbi->fb.var.xres = inf->xres;
- fbi->fb.var.xres_virtual = inf->xres;
- fbi->max_yres = inf->yres;
- fbi->fb.var.yres = inf->yres;
- fbi->fb.var.yres_virtual = inf->yres;
- fbi->max_bpp = inf->bpp;
- fbi->fb.var.bits_per_pixel = inf->bpp;
- fbi->fb.var.pixclock = inf->pixclock;
- fbi->fb.var.hsync_len = inf->hsync_len;
- fbi->fb.var.left_margin = inf->left_margin;
- fbi->fb.var.right_margin = inf->right_margin;
- fbi->fb.var.vsync_len = inf->vsync_len;
- fbi->fb.var.upper_margin = inf->upper_margin;
- fbi->fb.var.lower_margin = inf->lower_margin;
- fbi->fb.var.sync = inf->sync;
- fbi->fb.var.grayscale = inf->cmap_greyscale;
- fbi->cmap_inverse = inf->cmap_inverse;
- fbi->cmap_static = inf->cmap_static;
- fbi->reg.lcdcon1 = inf->reg.lcdcon1;
- fbi->reg.lcdcon2 = inf->reg.lcdcon2;
- fbi->reg.lcdcon3 = inf->reg.lcdcon3;
- fbi->reg.lcdcon4 = inf->reg.lcdcon4;
- fbi->reg.lcdcon5 = inf->reg.lcdcon5;
- fbi->state = C_STARTUP;
- fbi->task_state = (u_char)-1;
- fbi->fb.fix.smem_len = fbi->max_xres * fbi->max_yres *
- fbi->max_bpp / 8;
- init_waitqueue_head(&fbi->ctrlr_wait);
- INIT_WORK(&fbi->task, gzliu_fb_task, fbi);
- init_MUTEX(&fbi->ctrlr_sem);
- return fbi;
- }
- // add by
- static void s3c2410fb_irq_fifo(int irq, void *dev_id, struct pt_regs *regs)
- {
- printk("@@@@@@@@@@ s3c2410fb_irq_fifo() @@@@@@@@@@@@\n");
- volatile register int a,b;
- local_irq_disable();
- __raw_writel(__raw_readl(S3C2410_LCDINTMSK)|=3, S3C2410_LCDINTMSK);
- __raw_writel(1, S3C2410_LCDSRCPND);
- __raw_writel(1, S3C2410_LCDINTPND);
- __raw_writel(__raw_readl(S3C2410_LCDINTMSK)&=(~(1)), S3C2410_LCDINTMSK);
- b=0;
- for(a=0;a<2000;a++)b++;
- printk("@@@@@@@@ irq: %d @@@@@@@@@\n", irq);
- ClearPending(irq);
- }
- int __init gzliu_fb_probe(struct device *dev)
- {
- printk("@@@@@@@@@@ gzliu_fb_probe() @@@@@@@@@@@@\n");
- struct gzliu_fb_info *fbi;
- struct gzliu_fb_mach_info *inf;
- unsigned long flags;
- int ret;
- printk(KERN_ERR "gzliu_fb_probe start!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
- inf = &fs2410_info;//dev->platform_data;
- ret = -ENOMEM;
- fbi = NULL;
- if (!inf)
- goto failed;
- dev_dbg(dev, "got a %dx%dx%d LCD\n",inf->xres, inf->yres, inf->bpp);
- if (inf->xres == 0 || inf->yres == 0 || inf->bpp == 0) {
- dev_err(dev, "Invalid resolution or bit depth\n");
- ret = -EINVAL;
- goto failed;
- }
- gzliu_fb_backlight_power = inf->gzliu_fb_backlight_power;
- gzliu_fb_lcd_power = inf->gzliu_fb_lcd_power;
- fbi = gzliu_fb_init_fbinfo(dev);
- if (!fbi) {
- dev_err(dev, "Failed to initialize framebuffer device\n");
- ret = -ENOMEM;
- goto failed;
- }
- /* Initialize video memory */
- ret = gzliu_fb_map_video_memory(fbi);
- if (ret) {
- dev_err(dev, "Failed to allocate video RAM: %d\n", ret);
- ret = -ENOMEM;
- goto failed;
- }
- /*
- * This makes sure that our colour bitfield
- * descriptors are correctly initialised.
- */
- gzliu_fb_check_var(&fbi->fb.var, &fbi->fb);
- gzliu_fb_set_par(&fbi->fb);
- /*
- * include/linux/device.h
- *
- * static inline void dev_set_drvdata (struct device *dev, void *data)
- * {
- * dev->driver_data = data;
- * }
- */
- dev_set_drvdata(dev, fbi);
- /*
- * drivers/vedio/fbmem.c
- *
- * int register_framebuffer(struct fb_info *fb_info)
- * {
- * int i;
- * struct fb_event event;
- *
- * if (num_registered_fb == FB_MAX)
- * return -ENXIO;
- * num_registered_fb++;
- * for (i = 0 ; i < FB_MAX; i++)
- * if (!registered_fb[i])
- * break;
- * fb_info->node = i;
- *
- * fb_info->class_device = class_simple_device_add(fb_class, MKDEV(FB_MAJOR, i),
- * fb_info->device, "fb%d", i);
- * if (IS_ERR(fb_info->class_device)) {
- * // Not fatal //
- * printk(KERN_WARNING "Unable to create class_device for framebuffer %d; errno = %ld\n", i, PTR_ERR(fb_info->class_device));
- * fb_info->class_device = NULL;
- * } else
- * fb_init_class_device(fb_info);
- *
- * if (fb_info->pixmap.addr == NULL) {
- * fb_info->pixmap.addr = kmalloc(FBPIXMAPSIZE, GFP_KERNEL);
- * if (fb_info->pixmap.addr) {
- * fb_info->pixmap.size = FBPIXMAPSIZE;
- * fb_info->pixmap.buf_align = 1;
- * fb_info->pixmap.scan_align = 1;
- * fb_info->pixmap.access_align = 4;
- * fb_info->pixmap.flags = FB_PIXMAP_DEFAULT;
- * }
- * }
- * fb_info->pixmap.offset = 0;
- *
- * if (!fb_info->modelist.prev ||
- * !fb_info->modelist.next ||
- * list_empty(&fb_info->modelist)) {
- * struct fb_videomode mode;
- *
- * INIT_LIST_HEAD(&fb_info->modelist);
- * fb_var_to_videomode(&mode, &fb_info->var);
- * fb_add_videomode(&mode, &fb_info->modelist);
- * }
- *
- * registered_fb[i] = fb_info;
- *
- * devfs_mk_cdev(MKDEV(FB_MAJOR, i), S_IFCHR | S_IRUGO | S_IWUGO, "fb/%d", i);
- * event.info = fb_info;
- * notifier_call_chain(&fb_notifier_list, FB_EVENT_FB_REGISTERED, &event);
- * return 0;
- * }
- *
- */
- ret = register_framebuffer(&fbi->fb);
- if (ret < 0) {
- dev_err(dev, "Failed to register framebuffer device: %d\n", ret);
- goto failed;
- }
- printk("success to register framebuffer device: %d!!!\n", ret);
- // add by
- disable_irq(IRQ_LCD);
- ret = request_irq(IRQ_LCD, s3c2410fb_irq_fifo, SA_INTERRUPT, "LCD", fbi);
- if (ret) {
- printk(KERN_ERR "s3c2440fb: request_irq failed: %d\n", ret);
- goto failed;
- }
- enable_irq(IRQ_LCD);
- /*
- * Ok, now enable the LCD controller
- */
- set_ctrlr_state(fbi, C_ENABLE);
- printk("@@@@@@@ done probe @@@@@@@@\n");
- return 0;
- failed:
- dev_set_drvdata(dev, NULL);
- if (fbi)
- kfree(fbi);
- return ret;
- }/* int __init gzliu_fb_probe() */
- static struct device_driver gzliu_fb_driver = {
- .name = "s3c2410-lcd",
- .bus = &platform_bus_type,
- .probe = gzliu_fb_probe,
- };
- int __devinit s3c2410fb_init(void)
- {
- printk("@@@@@@@@@@ s3c2410fb_init() @@@@@@@@@@@@\n");
- int ret;
- printk("@@@@@ --- s3c2410fb init --- @@@@@\n");
- ret = driver_register(&gzliu_fb_driver);
- if(ret)
- printk("register device driver failed, return code is %d\n", ret);
- __raw_writel(__raw_readl(S3C2410_LCDINTMSK)|=3, S3C2410_LCDINTMSK);
- __raw_writel(1, S3C2410_LCDSRCPND);
- __raw_writel(1, S3C2410_LCDINTPND);
- __raw_writel(__raw_readl(S3C2410_LCDINTMSK)&=(~(1)), S3C2410_LCDINTMSK);
- return ret;
- }
- module_init(s3c2410fb_init);
- MODULE_AUTHOR("gzliu_hit@qq.com");
- MODULE_DESCRIPTION("framebuffer driver for s3c2440");
- MODULE_LICENSE("GPL");
- /*
- * linux/drivers/video/s3c2410fb.h
- */
- #ifndef __GZLIU_FB_H__
- #define __GZLIU_FB_H__
- /* Shadows for LCD controller registers */
- struct gzliu_fb_lcd_reg {
- unsigned long lcdcon1;
- unsigned long lcdcon2;
- unsigned long lcdcon3;
- unsigned long lcdcon4;
- unsigned long lcdcon5;
- unsigned long lcdsaddr1;
- unsigned long lcdsaddr2;
- unsigned long lcdsaddr3;
- };
- struct gzliu_fb_info {
- struct fb_info fb;
- struct device *dev;
- u_int max_bpp;
- u_int max_xres;
- u_int max_yres;
- /*
- * These are the addresses we mapped
- * the framebuffer memory region to.
- */
- /* raw memory addresses */
- dma_addr_t map_dma; /* physical */
- u_char * map_cpu; /* virtual */
- u_int map_size;
- /* addresses of pieces placed in raw buffer */
- u_char * screen_cpu; /* virtual address of frame buffer */
- dma_addr_t screen_dma; /* physical address of frame buffer */
- u16 * palette_cpu; /* virtual address of palette memory */
- dma_addr_t palette_dma; /* physical address of palette memory */
- u_int palette_size;
- /* DMA descriptors */
- dma_addr_t dmadesc_fblow_dma;
- dma_addr_t dmadesc_fbhigh_dma;
- dma_addr_t dmadesc_palette_dma;
- u_int cmap_inverse:1,
- cmap_static:1,
- unused:30;
- volatile u_char state;
- volatile u_char task_state;
- struct semaphore ctrlr_sem;
- wait_queue_head_t ctrlr_wait;
- struct work_struct task;
- struct gzliu_fb_lcd_reg reg;
- #ifdef CONFIG_CPU_FREQ
- struct notifier_block freq_transition;
- struct notifier_block freq_policy;
- #endif
- };
- struct gzliu_fb_mach_info {
- u_long pixclock;
- u_short xres;
- u_short yres;
- u_char bpp;
- u_char hsync_len;
- u_char left_margin;
- u_char right_margin;
- u_char vsync_len;
- u_char upper_margin;
- u_char lower_margin;
- u_char sync;
- u_int cmap_greyscale:1,
- cmap_inverse:1,
- cmap_static:1,
- unused:29;
- struct gzliu_fb_lcd_reg reg;
- void (*gzliu_fb_backlight_power)(int);
- void (*gzliu_fb_lcd_power)(int);
- };
- /*
- * Debug macros
- */
- //#define DEBUG 1
- #if DEBUG
- # define DPRINTK(fmt, args...) printk("%s: " fmt, __FUNCTION__ , ## args)
- #else
- # define DPRINTK(fmt, args...)
- #endif
- #define TO_INF(ptr,member) container_of(ptr,struct gzliu_fb_info,member)
- /*
- * These are the actions for set_ctrlr_state
- */
- #define C_DISABLE (0)
- #define C_ENABLE (1)
- #define C_DISABLE_CLKCHANGE (2)
- #define C_ENABLE_CLKCHANGE (3)
- #define C_REENABLE (4)
- #define C_DISABLE_PM (5)
- #define C_ENABLE_PM (6)
- #define C_STARTUP (7)
- #define GZLIU_NAME "GZLIU"
- /*
- * Minimum X and Y resolutions
- */
- #define MIN_XRES 64
- #define MIN_YRES 64
- #ifndef __ASSEMBLY__
- #define UData(Data) ((unsigned long) (Data))
- #else
- #define UData(Data) (Data)
- #endif
- #define Fld(Size, Shft) (((Size) << 16) + (Shft))
- #define FSize(Field) ((Field) >> 16)
- #define FShft(Field) ((Field) & 0x0000FFFF)
- #define FMsk(Field) (((UData (1) << FSize (Field)) - 1) << FShft (Field))
- #define FInsrt(Value, Field) \
- (UData (Value) << FShft (Field))
- #define fLCD2_LINEVAL Fld(10,14) /* TFT/STN: vertical size of LCD */
- #define LCD2_LINEVAL(x) FInsrt((x), fLCD2_LINEVAL)
- #define LCD2_LINEVAL_MSK FMsk(fLCD2_LINEVAL)
- #define fLCD3_HOZVAL Fld(11,8) /* horizontal size of LCD */
- #define LCD3_HOZVAL(x) FInsrt((x), fLCD3_HOZVAL)
- #define LCD3_HOZVAL_MSK FMsk(fLCD3_HOZVAL)
- #define fLCDADDR_BANK Fld(9,21) /* bank location for video buffer */
- #define LCDADDR_BANK(x) FInsrt((x), fLCDADDR_BANK)
- #define fLCDADDR_BASEU Fld(21,0) /* address of upper left corner */
- #define LCDADDR_BASEU(x) FInsrt((x), fLCDADDR_BASEU)
- #define fLCDADDR_BASEL Fld(21,0) /* address of lower right corner */
- #define LCDADDR_BASEL(x) FInsrt((x), fLCDADDR_BASEL)
- #define fLCDADDR_OFFSET Fld(11,11) /* Virtual screen offset size
- (# of half words) */
- #define LCDADDR_OFFSET(x) FInsrt((x), fLCDADDR_OFFSET)
- #define fLCDADDR_PAGE Fld(11,0) /* Virtual screen page width
- (# of half words) */
- #define LCDADDR_PAGE(x) FInsrt((x), fLCDADDR_PAGE)
- #endif /* __GZLIU_FB_H__ */
评论暂时关闭