zoukankan      html  css  js  c++  java
  • 9.LCD驱动架构

    1.小结

    1.分配一个fb_info
    2.设置

    • 2.1固定的参数
    • 2.2设置可变的参数
    • 2.3设置具体的文件操作指针fb_info->fbops
    • 2.4其他设置

    3.硬件相关操作

    • 3.1配置GPIO用于LCD
    • 3.2根据LCD手册设置LCD控制器,如VCLK的频率等
    • 3.3分配显存framebuffer并把地址告诉LCD控制器

    4.注册

    • 4.1分配显存fb_info->screnn_base,使用dma_alloc_writecombine()
       注:函数返回值是虚拟地址,有参数*handler返回实际实际物理地址,这个物理地址需要设置到LCD控制器
    • 4.2注册fb_info结构体,register_framebuffer

    5.出口

    • 5.1卸载内核中的fb_info
    • 5.2控制LCDCON1关闭PWREN信号,关背光,iounmap注销地址
    • 5.3释放DMA缓冲地址dma_free_write()
    • 5.4释放fb_info

    2.关键函数和数据结构

    • dma_alloc_writecombine
      分配内存空间

      void *dma_alloc_writecombine(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp)
      解析:
            返回值:申请到的DMA缓冲区虚拟地址,若为NULL则表示分配失败,此时需要使用dma_free_writecombine释放内存
            *dev:   这里填0,表示这个申请的缓冲区里没有内容
            size:   分配的地址大小(字节单位)
            *handle: 申请到的物理起始地址
            gfp:     分配出来的内存参数,标志定义在<linux/gfp.h>常用如下:
                      GFP_ATOMIC:用来从中断处理和进程上下文之外的其他代码中分配内存,从不睡眠
                      GFP_KERNEL:内核内存的正常分配,可能会睡眠
                      GFP_USER:  用来为用户空间也分配,可能会睡眠 
      

    framebuffer_alloc
    —创建一个新的帧缓冲区信息结构

    struct fb_info *framebuffer_alloc(size_t size, struct device *dev)  
    

    fb_info

    struct fb_info {
    	atomic_t count;
    	int node;
    	int flags;
    	struct mutex lock;		/* Lock for open/release/ioctl funcs */
    	struct mutex mm_lock;		/* Lock for fb_mmap and smem_* fields */
    	struct fb_var_screeninfo var;	/* Current var */
    	struct fb_fix_screeninfo fix;	/* Current fix */
    	struct fb_monspecs monspecs;	/* Current Monitor specs */
    	struct work_struct queue;	/* Framebuffer event queue */
    	struct fb_pixmap pixmap;	/* Image hardware mapper */
    	struct fb_pixmap sprite;	/* Cursor hardware mapper */
    	struct fb_cmap cmap;		/* Current cmap */
    	struct list_head modelist;      /* mode list */
    	struct fb_videomode *mode;	/* current mode */
      #ifdef CONFIG_FB_BACKLIGHT
    	/* assigned backlight device */
    	/* set before framebuffer registration, 
    	   remove after unregister */
    	struct backlight_device *bl_dev;
    
    	/* Backlight level curve */
    	struct mutex bl_curve_mutex;	
    	u8 bl_curve[FB_BACKLIGHT_LEVELS];
      #endif
      #ifdef CONFIG_FB_DEFERRED_IO
    	struct delayed_work deferred_work;
    	struct fb_deferred_io *fbdefio;
      #endif
    
    	struct fb_ops *fbops;
    	struct device *device;		/* This is the parent */
    	struct device *dev;		/* This is this fb device */
    	int class_flag;                    /* private sysfs flags */
      #ifdef CONFIG_FB_TILEBLITTING
    	struct fb_tile_ops *tileops;    /* Tile Blitting */
      #endif
    	char __iomem *screen_base;	/* Virtual address */
    	unsigned long screen_size;	/* Amount of ioremapped VRAM or 0 */ 
    	void *pseudo_palette;		/* Fake palette of 16 colors */ 
      #define FBINFO_STATE_RUNNING	0
      #define FBINFO_STATE_SUSPENDED	1
    	u32 state;			/* Hardware state i.e suspend */
    	void *fbcon_par;                /* fbcon use-only private area */
    	/* From here on everything is device dependent */
    	void *par;
    	/* we need the PCI or similar aperture base/size not
    	   smem_start/size as smem_start may just be an object
    	   allocated inside the aperture so may not actually overlap */
    	struct apertures_struct {
    		unsigned int count;
    		struct aperture {
    			resource_size_t base;
    			resource_size_t size;
    		} ranges[0];
    	} *apertures;
    };
    
    • register_framebuffer
      注册一个帧缓冲设备

      int register_framebuffer(struct fb_info *fb_info)
      

    3.源码解析

    lcd.c

      #define LCD_xres	480
      #define LCD_yres	270
    
    static u32 pseudo_palette[16];
    
    static struct fb_info *mylcd_info;
    
    static volatile unsigned long *GPBcon;
    static volatile unsigned long *GPCcon;
    static volatile unsigned long *GPDcon;
    static volatile unsigned long *GPGcon;		//GPG4:控制LCD信号
    static volatile unsigned long *GPBdat;		//GPB0: 控制背光
    
    /*	lcd  control	*/
    static struct 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;
    
    	unsigned long redlut;   
    	unsigned long greenlut;
    	unsigned long bluelut;
    	unsigned long reserved[9];  
    	unsigned long dithmode;     
    	unsigned long tpal ;            
    	unsigned long lcdintpnd;
    	unsigned long lcdsrcpnd;
    	unsigned long lcdintmsk;
    	unsigned long tconsel;  
    
    } *lcd_reg;
    
    /*	把单色提出来,放到rgb中对应的位置	*/
    static inline unsigned int chan_to_field(unsigned int chan, struct fb_bitfield *bf)
    {
    	chan &= 0xffff;
    	chan >>= 16 - bf->length;
    	return chan << bf->offset;
    }
    
    
    /*	设置调色板供内核调用	*/
    static int mylcd_fb_setcolreg(unsigned int regno, unsigned int red, unsigned int green, unsigned int blue, unsigned int transp, struct fb_info *info)
    {
    	unsigned int val;
    
    	if(regno >= 16)
    		return 1;		//调色板数组不能大于15
    
    	val = chan_to_field(red, &info->var.red);
    	val |= chan_to_field(green, &info->var.green);
    	val |= chan_to_field(blue, &info->var.blue);
    
    	pseudo_palette[regno] = val;
    	return 0;
    }
    
    
    static struct fb_ops mylcd_fb_ops = {
    	.owner = THIS_MODULE,
    	.fb_setcolreg = mylcd_fb_setcolreg,
    	.fb_fillrect = cfb_fillrect,            //填充矩形
    	.fb_copyarea = cfb_copyarea,            //复制数据
    	.fb_imageblit = cfb_imageblit,          //绘画图像
    };
    
    static int lcd_init(void)
    {
    	printk(KERN_DEBUG"%s %s %d
    ", __FILE__, __FUNCTION__, __LINE__);
    	/*	1.申请fb_info结构体	*/
    	mylcd_info = framebuffer_alloc(0, 0);
    	
    	/*	2.设置	*/
    	/*	2.1设置固定参数	*/
    	strcpy(mylcd_info->fix.id, "mylcd");					//名字
    	mylcd_info->fix.smem_len = LCD_xres * LCD_yres * 2;		//长度(像素为16bit[2字节],所以乘以2)
    	mylcd_info->fix.type     = FB_TYPE_PACKED_PIXELS;		//支持的类型
    	mylcd_info->fix.visual	 = FB_VISUAL_TRUECOLOR;			//真彩色
    	mylcd_info->fix.line_length = LCD_xres * 2;                     //同上
    	
    	printk(KERN_DEBUG"%s %s %d
    ", __FILE__, __FUNCTION__, __LINE__);
    	/*	2.2设置可变参数	*/
    	mylcd_info->var.xres = 480;				//可见屏x分辨率
    	mylcd_info->var.yres = 270;				//可见屏y分辨率
    	mylcd_info->var.xres_virtual = 480;		//虚拟屏x分辨率
    	mylcd_info->var.yres_virtual = 270;		//虚拟屏y分辨率
    	mylcd_info->var.xoffset = 0;			//虚拟屏到可见屏之间x偏移
    	mylcd_info->var.yoffset = 0;			//y偏移
    
    	mylcd_info->var.bits_per_pixel = 16;	//像素
    	mylcd_info->var.grayscale = 0;			//灰度(透明度)
    	
    	
    	printk(KERN_DEBUG"%s %s %d
    ", __FILE__, __FUNCTION__, __LINE__);
    	/*	rgb:565	*/
    	mylcd_info->var.red.offset = 11;		//偏移位置
    	mylcd_info->var.red.length = 5;			//长度
    	mylcd_info->var.green.offset = 5;
    	mylcd_info->var.green.length = 6;
    	mylcd_info->var.blue.offset	= 0;
    	mylcd_info->var.blue.length = 5;
    		 
    	/*	2.3设置操作函数	*/
    	mylcd_info->fbops = &mylcd_fb_ops;
    
    	printk(KERN_DEBUG"%s %s %d
    ", __FILE__, __FUNCTION__, __LINE__);
    	/*	2.4设置其他	*/
    	mylcd_info->pseudo_palette = pseudo_palette;		//保存调色板数组
    	mylcd_info->screen_size = LCD_xres * LCD_yres * 2;	//虚拟地址长
    	
    	/*	3.硬件操作		*/
    	/*	3.1设置gpio为lcd	*/
    	GPBcon = ioremap(0x56000010, 8);
    	GPBdat = GPBcon + 1;
    	GPCcon = ioremap(0x56000020, 4);
    	GPDcon = ioremap(0x56000030, 4);
    	GPGcon = ioremap(0x56000060, 4);
    
    	*GPBcon &= ~(0X3 << 0);
    	*GPBcon |= (0X1 << 0);		//输出
    	*GPBdat &= ~(0X1 << 0);		//关背光
    
    	*GPCcon = 0Xaaaaaaaa;
    	*GPDcon = 0Xaaaaaaaa;
    	*GPGcon |= (0x3 << (4 * 2));	//lcd_power
    	
    	/*	3.2设置lcd控制器	*/
    	lcd_reg->lcdcon1 = (4<<8) | (3<<5) | (0xc<<1);
    	lcd_reg->lcdcon2 = (3<<24) | (271<<14) | (1<<6) |(0<<0);
    	lcd_reg->lcdcon3 = ((16)<<19) | (479<<8) | ((10));
    	lcd_reg->lcdcon4 = (4);
    	lcd_reg->lcdcon5 = (1<<11) | (1<<9) | (1<<8)|(1<<0);	  
    
    	lcd_reg->lcdcon1 &= ~(1<<0);	//关闭PWREN信号输出
    	lcd_reg->lcdcon5 &= ~(1<<3);	 //禁止PWREN信号
    
    	/*	3.3分配显存	*/
    	mylcd_info->screen_base = dma_alloc_writecombine(0, mylcd_info->fix.smem_len, mylcd_info->fix.smem_start, GFP_KERNEL);            //显存虚拟地址
    
    	lcd_reg->lcdsaddr1 = (mylcd_info->fix.smem_start >> 1) & (0x3fffffff);
    	lcd_reg->lcdsaddr2 = ((mylcd_info->fix.smem_start + mylcd_info->screen_size) >> 1) & 0x1fffff;
    	lcd_reg->lcdsaddr3 = LCD_xres & 0x3ff;
    
    	/*	4.1开启lcd	*/
    	lcd_reg->lcdcon1 |= (1 << 0);		//输出power信号
    	lcd_reg->lcdcon2 |= (1 << 3);		//允许power信号
    	*GPBdat |= (1 << 0);				//开背光
    	
    	/*	4.2注册fb_info	*/
    	register_framebuffer(mylcd_info);
    
    	return 0;
    }
    
    static int lcd_exit(void)
    {
    	printk(KERN_DEBUG"%s %s %d
    ", __FILE__, __FUNCTION__, __LINE__);
    	
    	/*	1.卸载fb_info	*/
    	unregister_framebuffer(mylcd_info);
    	
    	/*	2.控制lcd关闭,释放io	*/
    	lcd_reg->lcdcon1 &= ~(1 << 0);
    	lcd_reg->lcdcon5 &= ~(1 << 3);
    	*GPBdat &= ~(1 << 0);
    
    	iounmap(GPBcon);
    	iounmap(GPCcon);
    	iounmap(GPDcon);
    	iounmap(GPGcon);
    	
    	/*	3.释放显存	*/
    	dma_free_writecombine(0, mylcd_info->screen_size, mylcd_info->screen_base, mylcd_info->fix.smem_start);
    	
    	/*	4.释放fb_info	*/
    	framebuffer_release(mylcd_info);
    
    	return 0;
    }
    
    module_init(lcd_init);
    module_exit(lcd_exit);
    MODULE_LICENSE("GPL");
    

    Makefile

    KERN_DIR = /home/book/linux-2.6.22.6
    
    all:
    	make -C $(KERN_DIR) M=`pwd` modules 
    
    clean:
    	make -C $(KERN_DIR) M=`pwd` modules clean
    	rm -rf modules.order
    
    obj-m	+= lcd.o
  • 相关阅读:
    性能测试方案和用例模板
    软件质量报告模板-产品质量度量
    性能测试报告模板
    SQL查询语法30例
    性能测试:Jmeter-Beanshell请求加密实例
    安全性测试:OWASP ZAP 2.8 使用指南(三):ZAP代理设置
    centos7下使用x11远程带窗口安装Oracle
    python Linux 环境 (版本隔离工具)
    Python多版本环境搭建(Linux系统)
    ArrayList1.8
  • 原文地址:https://www.cnblogs.com/huangdengtao/p/13338282.html
Copyright © 2011-2022 走看看