📄 bf537_lq035fb.c
字号:
/* * drivers/video/bf537_lq035fb.c * Analog Devices Blackfin(BF537 STAMP) + TFT LCD. * */#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/delay.h>#include <linux/fb.h>#include <linux/ioport.h>#include <linux/init.h>#include <linux/types.h>#include <linux/interrupt.h>#include <linux/sched.h>#include <linux/timer.h>#include <linux/device.h>#include <linux/dma-mapping.h>#include <linux/platform_device.h>#include <asm/blackfin.h>#include <asm/irq.h>#include <asm/dpmc.h>#include <asm/dma-mapping.h>#include <asm/dma.h>#include <asm/uaccess.h>#include <asm/semaphore.h>#include <asm/mach/cdefBF537.h>//fb#define START_LINES 8#define U_LINES (9)#define LCD_XRES 320 /**< \brief Width.*/#define LCD_YRES 240 /**< \brief Height.*/#define LCD_BPP 16 /**< \brief Bits per pixel.*/#define BYTES_PER_ROW ((LCD_XRES / 8) * LCD_BPP)#define UPPER_MARGIN 19#define LOWER_MARGIN 4#define FB_BUFSIZE ((LCD_XRES * LCD_YRES / 8) * LCD_BPP) /**< \brief Size of Framebuffer.*/#define FB_BUFSIZE_DMA ((LCD_XRES * (LCD_YRES+UPPER_MARGIN+LOWER_MARGIN) / 8) * LCD_BPP)#define Th 408#define Ths 30#define Tv (Th * 263)#define Tvs (Th * 4)#define Tep 320/* IHS-DEN time min 36 type 68 max 88*/#define The 68/* IVS-DEN time type 18 * Th*/#define Tve (18 * Th)/* when SYNC mode is used, 1st data start from 68th CLK afer IHS failing.*/#define LATENCY_AFTER_Hv 68#define _DEBUG#ifdef _DEBUG #define DBG(args...) printk(args)#else#define DBG(args...) do{} while(0)#endifstatic volatile int open_count;static struct fb_info bfin_lq035_fb;/* only one program can use framebuffer device.*/static struct semaphore sem_one;static u16* fb_buffer; /* RGB Buffer */static dma_addr_t dma_handle; /* ? */static u32 lq035_fb_pseudo_palette[16];static struct fb_var_screeninfo bfin_lq035_fb_defined = { .xres = LCD_XRES, .yres = LCD_YRES, .xres_virtual = LCD_XRES, .yres_virtual = LCD_YRES, .bits_per_pixel = LCD_BPP, .activate = FB_ACTIVATE_NOW, .height = -1, .width = -1, .pixclock = ((u32)1000000 / 3.58), .left_margin = LATENCY_AFTER_Hv, .right_margin = Th - LATENCY_AFTER_Hv - LCD_XRES, .upper_margin = UPPER_MARGIN * Th, .lower_margin = LOWER_MARGIN * Th, .hsync_len = Ths, .vsync_len = Tvs, /* Interpretation of offset for color fields: All offsets are from the right, * inside a "pixel" value, which is exactly 'bits_per_pixel' wide (means: you * can use the offset as right argument to <<). A pixel afterwards is a bit * stream and is written to video memory as that unmodified. This implies * big-endian byte order if bits_per_pixel is greater than 8. * * struct fb_bitfield * { * __u32 offset; beginning of bitfield * __u32 length; length of bitfield * __u32 msb_right; != 0 : Most significant bit is * } * so RGB2PIXEL should be * if (TRUECOLOR) * { * pixel = (B>>(16-b.len))<<b.off | (G>>(16-g.len))<<g.off | (R>>(16-r.len))<<r.off; * } */ .red = {11, 5, 0}, .green = {5, 6, 0}, .blue = {0, 5, 0}, .transp = {0, 0, 0},};static struct fb_fix_screeninfo bfin_lq035_fb_fix __initdata = { .id = "BF537_lq035fb", .smem_len = FB_BUFSIZE, .type = FB_TYPE_PACKED_PIXELS, .visual = FB_VISUAL_TRUECOLOR, .xpanstep = 0, .ypanstep = 0, .line_length = BYTES_PER_ROW, .accel = FB_ACCEL_NONE,};static void config_timers (void) /* CHECKME */{ /* timer0 h_sync timer1 v_sync timer2 DN */ bfin_write_TIMER_DISABLE(TIMDIS0 | TIMDIS1 | TIMDIS2); __builtin_bfin_ssync(); /* TIMER0 is used for H-sync. */ bfin_write_TIMER0_CONFIG(PWM_OUT | PERIOD_CNT | CLK_SEL | TIN_SEL | EMU_RUN); bfin_write_TIMER0_WIDTH(Ths);//Ths = 30 bfin_write_TIMER0_PERIOD(Th);//Th = 408 __builtin_bfin_ssync(); bfin_write_TIMER1_CONFIG(PWM_OUT | PERIOD_CNT | CLK_SEL | TIN_SEL | EMU_RUN); bfin_write_TIMER1_WIDTH(Tvs);//3*Th=1224 4*Th=1632 MAX=5*Th=2040 bfin_write_TIMER1_PERIOD(Tv);//262.5*Th 263*Th=107304 __builtin_bfin_ssync(); /* the pin should fixed low,because this driver used SYNC mode. so both WIDTH and PERIOD are useless. */ bfin_write_TIMER2_CONFIG(PWM_OUT | PERIOD_CNT | CLK_SEL | TIN_SEL | EMU_RUN | PULSE_HI); bfin_write_TIMER2_WIDTH(Tep);//Tep=320 bfin_write_TIMER2_PERIOD(Th);//Th __builtin_bfin_ssync();}static int config_dma (void){ assert(fb_buffer); if (request_dma(CH_PPI, "BF537_PPI_DMA") < 0) return -EFAULT; set_dma_config(CH_PPI, set_bfin_dma_config(DIR_READ, DMA_FLOW_AUTO, INTR_DISABLE, DIMENSION_2D, DATA_SIZE_16)); set_dma_x_count(CH_PPI, LCD_XRES); set_dma_x_modify(CH_PPI, 2); set_dma_y_count(CH_PPI, LCD_YRES + UPPER_MARGIN + LOWER_MARGIN); set_dma_y_modify(CH_PPI, 2); set_dma_start_addr(CH_PPI, ((unsigned long)fb_buffer)); return 0;}static void config_ppi (void){ bfin_write_PPI_CONTROL((POLS | DLEN_16 | 0x10 | XFR_TYPE | PORT_DIR) & (~PORT_EN)); /* after PPI_FS1 is asserted, there is a latency of 1 PPI_CLK cylc, and then there is a delay for the number of PPI_CLK cycles programmed into PPI_DELAY. No further DMA takes place until the next PPI_FS1 sync. so the latency should minus one. */ bfin_write_PPI_DELAY(LATENCY_AFTER_Hv - 1); /* this register holds the number of samples to write out through the PPI per line, minus one. */ bfin_write_PPI_COUNT(LCD_XRES - 1);}static void init_ports(void){ //*pEBIU_AMGCTL |= 0x0100; bfin_write_EBIU_AMGCTL(bfin_read_EBIU_AMGCTL() | 0x0100); //*pPORTG_FER |= 0xffff; bfin_write_PORTG_FER(bfin_read_PORTG_FER() | 0xffff); //*pPORTF_FER |= 0xffc0; bfin_write_PORTF_FER(bfin_read_PORTF_FER() | 0xffc0); //*pPORTF_FER &= ~((1U<<0)|(1U<<1)|(1U<<2)|(1U<<3)|(1U<<4)|(1U<<5)); __builtin_bfin_ssync();}static int bfin_lq035_fb_mmap(struct fb_info *info, struct vm_area_struct * vma){ DBG("on mapping\n"); vma->vm_start = (unsigned long)(fb_buffer) + (LCD_XRES * UPPER_MARGIN * LCD_BPP / 8); vma->vm_end = vma->vm_start + FB_BUFSIZE; vma->vm_flags |= VM_MAYSHARE; return 0;}static int bfin_lq035_fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info){ *var = info->var; return 0;}static int hw_init(void){ init_ports(); config_dma(); config_ppi(); config_timers(); __builtin_bfin_ssync(); bfin_write_PPI_CONTROL(bfin_read_PPI_CONTROL() | PORT_EN); __builtin_bfin_ssync(); enable_dma(CH_PPI); bfin_write_TIMER_ENABLE(TIMEN0 | TIMEN1); __builtin_bfin_ssync(); return 0; }static int hw_deinit(void){ bfin_write_TIMER_DISABLE(TIMDIS0 | TIMDIS1); __builtin_bfin_ssync(); bfin_write_PPI_CONTROL(bfin_read_PPI_CONTROL() & ~PORT_EN); __builtin_bfin_ssync(); free_dma(CH_PPI); return 0;}static int bfin_lq035_fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, u_int transp, struct fb_info *info){ u32 pseudo_val; DBG("setcolreg: %d: rgb=%d,%d,%d, tr=%d\n", regno, red, green, blue, transp); if (info->var.grayscale) red = green = blue = (19595*red + 38470*green + 7471*blue) >> 16; switch (info->fix.visual) { case FB_VISUAL_TRUECOLOR: if (regno >= 16) return -EINVAL; /* deal with creating pseudo-palette entries */ pseudo_val = (red >> (16 - info->var.red.length)) << info->var.red.offset; pseudo_val |= (green >> (16 - info->var.green.length)) << info->var.green.offset; pseudo_val |= (blue >> (16 - info->var.blue.length)) << info->var.blue.offset; DBG("setcolreg: pseudo %d, val %08x\n", regno, pseudo_val); ((u32 *)info->pseudo_palette)[regno] = pseudo_val; break; case FB_VISUAL_PSEUDOCOLOR: break; default: return -ENOSYS; } return 0; }static struct fb_ops bfin_lq035_fb_ops = { .owner = THIS_MODULE, .fb_mmap = bfin_lq035_fb_mmap, .fb_setcolreg = bfin_lq035_fb_setcolreg, .fb_fillrect = cfb_fillrect, .fb_copyarea = cfb_copyarea, .fb_imageblit = cfb_imageblit, .fb_check_var = bfin_lq035_fb_check_var,};static int __init bfin_lq035_fb_init(void){ DBG("LCD FrameBuffer initializing...\n"); init_MUTEX(&sem_one); ////allocate memory, fb_buffer is a pointer to char fb_buffer = dma_alloc_coherent(NULL, FB_BUFSIZE_DMA, &dma_handle, GFP_KERNEL); if (NULL == fb_buffer) { printk(KERN_ERR "BF537 FB: couldn't allocate dma buffer.\n"); return -ENOMEM; } ////initialise fb_buffer with 0xff memset(fb_buffer, 0xff, FB_BUFSIZE_DMA); ////bfin_lq035_fb is a struct of fb_info ////initialise address of buffer //bfin_lq035_fb.screen_base = (void*)fb_buffer; //bfin_lq035_fb_fix.smem_start = (int)fb_buffer; bfin_lq035_fb.screen_base = (void*)((u32)(fb_buffer) + (LCD_XRES * UPPER_MARGIN * LCD_BPP / 8)); bfin_lq035_fb_fix.smem_start = (u32)(fb_buffer) + (LCD_XRES * UPPER_MARGIN * LCD_BPP / 8); bfin_lq035_fb.fbops = &bfin_lq035_fb_ops; bfin_lq035_fb.var = bfin_lq035_fb_defined; bfin_lq035_fb.fix = bfin_lq035_fb_fix; bfin_lq035_fb.flags = FBINFO_DEFAULT; //bfin_lq035_fb.pseudo_palette = &lq035_fb_pseudo_palette; bfin_lq035_fb.pseudo_palette = lq035_fb_pseudo_palette; hw_init(); if (register_framebuffer(&bfin_lq035_fb) < 0) { printk(KERN_ERR "BF537 FB: unable to register framebuffer.\n"); dma_free_coherent(NULL, FB_BUFSIZE_DMA, fb_buffer, dma_handle); fb_buffer = NULL; return -EINVAL; } return 0;}static void __exit bfin_lq035_fb_exit(void){ hw_deinit(); if (NULL != fb_buffer) dma_free_coherent(NULL, FB_BUFSIZE_DMA, fb_buffer, dma_handle); unregister_framebuffer(&bfin_lq035_fb); DBG("Unregister LCD driver.\n");}#ifdef MODULEMODULE_LICENSE("GPL");#endifmodule_init(bfin_lq035_fb_init);module_exit(bfin_lq035_fb_exit);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -