LCD

版权声明:本文为博主原创文章,未经博主允许不得转载。
https://blog.csdn.net/huangweiqing80/article/details/82990736
为更好的了解Linux LCD子系统,我们先来看一下Linux LCD裸机驱动程序是怎么写的?
1.LCD裸机思维导图
在这里插入图片描述

2LCD裸机驱动
这里以TQ2440显示一张图片为例

#define GPCCON (*(volatile unsigned long *)0x56000020)
#define GPDCON (*(volatile unsigned long *)0x56000030)
#define GPGCON (*(volatile unsigned long *)0x56000060)
#define LCDCON1 (*(volatile unsigned long *)0x4D000000)
#define LCDCON2 (*(volatile unsigned long *)0x4D000004)
#define LCDCON3 (*(volatile unsigned long *)0x4D000008)
#define LCDCON4 (*(volatile unsigned long *)0x4D00000C)
#define LCDCON5 (*(volatile unsigned long *)0x4D000010)
#define LCDSADDR1 (*(volatile unsigned long *)0x4D000014)
#define LCDSADDR2 (*(volatile unsigned long *)0x4D000018)
#define LCDSADDR3 (*(volatile unsigned long *)0x4D00001C)
#define TPAL (*(volatile unsigned long *)0x4D000050)

#define VSPW 9
#define VBPD 1
#define LINEVAL 271
#define VFPD 1
#define CLKVAL 4   //10 = 100/((CLKVAL+1)*2)
#define HSPW 40
#define HBPD 1
#define HOZVAL 479
#define HFPD 1

unsigned short LCDBUFFER[272][480];

typedef unsigned int U32;
typedef unsigned short U16;
typedef unsigned char U8;

void lcd_port_init()
{
    GPDCON = 0xaaaaaaaa;
    GPCCON = 0xaaaaaaaa;		
}

void lcd_control_init()
{	
    LCDCON1 = (CLKVAL<<8)|(0x3<<5)|(0xc<<1)|(0<<0);
    LCDCON2 = (VBPD<<24)|(LINEVAL<<14)|(VFPD<<6)|(VSPW);
    LCDCON3 = (HBPD<<19)|(HOZVAL<<8)|(HFPD);
    LCDCON4 = (HSPW);
    LCDCON5 = (1<<11)|(1<<9)|(1<<8);
    
    LCDSADDR1 = (((U32)LCDBUFFER>>22)<<21) | (((U32)LCDBUFFER>>1)&0x1fffff);
    LCDSADDR2 = (((U32)LCDBUFFER+272*480*2)>>1)&0x1fffff;
    LCDSADDR3 = (0<<11) | (480*2/2);
    
    TPAL = 0;
}


void lcd_init()
{
    lcd_port_init();
    lcd_control_init();
    
    //打开LCD电源
    GPGCON |= (0x3<<8);
    LCDCON5 |= (1<<3);   
    LCDCON1 |= 1;
}

void point(unsigned int x,unsigned int y,unsigned int color)
{
    unsigned int red, green, blue;
    
    red = (color>>19) & 0x1f;
    green = (color>>10) & 0x3f;
    blue = (color>>3) & 0x1f;
    LCDBUFFER[y][x] = (unsigned short)((red<<11)|(green<<5)|blue);	
}

void Paint_Bmp(U16 x0,U16 y0,U16 wide,U16 high,const U8 *bmp)
{
    U16 x,y;
    U16 c;
    U32 p = 0;
    
    for( y = y0 ; y < y0+high ; y++ )
    {
    	for( x = x0 ; x < x0+wide ; x++ )
    	{
    	    c = bmp[p] | (bmp[p+1]<<8) ;										
	    
	    if ( ( x < 480) && ( y < 272) )
	        LCDBUFFER[y][x] = c ;
		
	    p = p + 2 ;	
    	}
    }
}

void clearSrc(unsigned int color)
{
    TPAL = (1<<24)|(color&0xffffff);	
}

extern unsigned char bmp[90200];

void lcd_test()
{
    int x;
    
    for(x=0;x<480;x++)
        point(x++,150,0xff0000);
        
    Paint_Bmp(0,0,220,220,bmp);
    
    clearSrc(0xff0000);
}

关于Linux LCD驱动程序的分析:LINUX下的LCD子系统分析

通过这篇文章我大概讲一下我的个人理解:

  1. LCD子系统是通过平台设备驱动模型来注册的,他有device和driver两个部分。
  2. framebuffer是为了封装LCD,提供统一的用户空间环境,这样在用户空间显示图片和读取图片就可以通过/dev/fb节点来操作
  3. framebuffer是在LCD driver 的probe函数中进行初始化和注册的
  4. probe函数中的下面函数的个人理解
    4.1 s3c2410fb_map_video_memory
    分配帧缓冲内存,unsigned short LCDBUFFER[272][480];
    4.2 s3c2410fb_init_registers
    设置引脚类型,对应LCD裸机中的引脚初始化 lcd_port_init
    4.3 s3c2410fb_set_par
    设置LCD控制器寄存器,对应LCD裸机中的时序初始化lcd_control_init
    5.关于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;
};

上面讲的是三星平台的LCD子系统架构,其他平台的架构会略有不同,但都大同小异,下面我们再来看一下MTK平台的LCD子系统
MTK LCD 驱动过程详解

这边我也补充一下:

  1. MTK 的LCD子系统同样也是通过平台设备驱动模型来驱动的,他同样也有device 和driver两部分,文中只讲了plateform_driver部分,plateform_device部分在source/mediatek/platform/mt6572/kernel/core/mt_devs.c
__init int mt_board_init(void)
{
    ...
    retval = platform_device_register(&mt6575_device_fb);
    ...
}
static struct platform_device mt6575_device_fb = {
    .name = "mtkfb",
    .id   = 0,
    .num_resources = ARRAY_SIZE(resource_fb),
    .resource      = resource_fb,
    .dev = {
        .dma_mask = &mtkfb_dmamask,
        .coherent_dma_mask = 0xffffffff,
    },
};

知道了MTK整个LCD子系统的架构,我们再来看MTK LCM的移植就很清楚了

1. LCD
1.1怎样新建一个LCD驱动
LCD模组主要包括LCD显示屏和驱动IC。比如LF040DNYB16a模组的驱动IC型号为NT35510。要在MT577平台上新建这个lcd的驱动,步骤如下:
A.      新建文件夹nt35510:
\mediatek\custom\common\kernel\lcm\nt35510
\mediatek\custom\common\lk\lcm\nt35510 //\mediatek\custom\common\uboot\lcm\nt35510 
 
B.修改\mediatek\custom\common\kernel\lcm\mt65xx_lcm_list.c, 在lcm_driver_list [ lcm_count ] 中增加nt35510_lcm_drv。
C.打开mediatek\config\ginwave73_gb\ProjectConfig.mk:
BUILD_LK=yes //BUILD_UBOOT=yes
BOOT_LOGO=wsvganl
 
CUSTOM_KERNEL_LCM = nt35510
CUSTOM_LK_LCM= nt35510 // CUSTOM_UBOOT_LCM =nt35510
 
LCM_WIDTH=600
LCM_HEIGHT=1024
驱动文件移植原则:
根据具体平台,填充对应的函数,不能直接复制整个文件,避免不必要编译和接口错误。

其他平台(如RK,IMX等)的LCM移植会不同,但是我们可以通过分析LCD子系统的架构便能很清晰的知道移植需要移植哪些东西

猜你喜欢

转载自blog.csdn.net/huangweiqing80/article/details/82990736
LCD