linux lcd设备驱动剖析一

s3c2440 lcd驱动源码文件是:drivers/video/s3c2410fb.c

看驱动源码首先当然是先看入口函数,这里是s3c2410fb_init函数

int __init s3c2410fb_init(void)
{
	/* 注册一个s3c2410fb_driver平台驱动 */
	int ret = platform_driver_register(&s3c2410fb_driver);

	if (ret == 0)
		ret = platform_driver_register(&s3c2412fb_driver);;

	return ret;
}
出口函数,自然是注销s3c2410fb_driver平台驱动

static void __exit s3c2410fb_cleanup(void)
{
	platform_driver_unregister(&s3c2410fb_driver);
	platform_driver_unregister(&s3c2412fb_driver);
}
我们研究的是s3c2440,只关心s3c2410fb_driver,s3c2412fb_driver不用理会。

static struct platform_driver s3c2410fb_driver = {
	.probe		= s3c2410fb_probe,
	.remove		= s3c2410fb_remove,
	.suspend	= s3c2410fb_suspend,
	.resume		= s3c2410fb_resume,
	.driver		= {
		.name	= "s3c2410-lcd",
		.owner	= THIS_MODULE,
	},
};
这里看到s3c2410fb_driver的name字段为s3c2410-lcd。回顾这钱前面章节说过的知识,如果linux系统中存在同名的平台设备时,就会调用平台驱动的probe函数。这里,如果存在有同名"s3c2410-lcd"的平台设备,就会调用s3c2410fb_driver的s3c2410fb_probe函数。

在source  insight搜索s3c2410-lcd,很快就能搜索到arch/arm/plat-s3c24xx/devs.c中有那么一段

struct platform_device s3c_device_lcd = {
	.name		  = "s3c2410-lcd",
	.id		  = -1,
	.num_resources	  = ARRAY_SIZE(s3c_lcd_resource),
	.resource	  = s3c_lcd_resource,
	.dev              = {
		.dma_mask		= &s3c_device_lcd_dmamask,
		.coherent_dma_mask	= 0xffffffffUL
	}
};

EXPORT_SYMBOL(s3c_device_lcd);
其中平台设备中比较重要的是成员是resource,这里是s3c_lcd_resource

static struct resource s3c_lcd_resource[] = {
	[0] = {
		.start = S3C24XX_PA_LCD,				/* 0x4D000000 */
		.end   = S3C24XX_PA_LCD + S3C24XX_SZ_LCD - 1,
		.flags = IORESOURCE_MEM,
	},
	[1] = {
		.start = IRQ_LCD,						/* IRQ = 32 */
		.end   = IRQ_LCD,
		.flags = IORESOURCE_IRQ,
	}

};

static u64 s3c_device_lcd_dmamask = 0xffffffffUL;
那么接下来当然是要分析probe函数了

static int __init s3c2410fb_probe(struct platform_device *pdev)
{
	return s3c24xxfb_probe(pdev, DRV_S3C2410);
}
s3c2410fb_probe函数调用s3c24xxfb_probe函数,这是lcd驱动的关键函数之一,留到"linux lcd设备驱动剖析二"再分析,但是在分析这个函数前,需要来熟悉一下几个结构体。

linux lcd驱动中有个关键词叫帧缓冲,它是linux为显示设备提供的一个接口,它允许应用程序在图形模式下直接对显示缓冲区进行读写操作,用户不必关心物理显示缓冲区的具体位置及存放方式,这些都由帧缓冲设备驱动本身来完成。

帧缓冲设备为标准字符设备,主设备号为29,对应/dev/fbn 设备文件,帧缓冲设备最关键的一个数据结构是fb_info结构体,它包括了关于帧缓冲设备属性和操作的完整描述。

struct fb_info {
	int node;						//用作次设备号索引
	int flags;
	struct mutex lock;				//用于open/release/ioctl函数的锁
	struct fb_var_screeninfo var;	//可变参数,重点
	struct fb_fix_screeninfo fix;	//固定参数,重点
	struct fb_monspecs monspecs;	//显示器标准
	struct work_struct queue;		//帧缓冲区队列
	struct fb_pixmap pixmap;		//图像硬件映射
	struct fb_pixmap sprite;		//光标硬件映射
	struct fb_cmap cmap;			//当前颜色表
	struct list_head modelist;      //模式链表
	struct fb_videomode *mode;		//当前video模式

	char __iomem *screen_base;		//显存基地址
	unsigned long screen_size;		//显存大小
	void *pseudo_palette;			//伪16色颜色表
#define FBINFO_STATE_RUNNING	0
#define FBINFO_STATE_SUSPENDED	1
	u32 state;						//硬件状态,如挂起
	void *fbcon_par;                //用作私有数据区
	void *par;						//info->par指向了额外多申请内存空间的首地址
};
s3c2410fb_info结构体,这是s3c2410抽像出来的特有信息

struct s3c2410fb_info {
	struct device		*dev;			//设备
	struct clk			*clk;			//时钟

	struct resource		*mem;			//资源
	void __iomem		*io;			//IO地址
	void __iomem		*irq_base;		//IRQ基数

	enum s3c_drv_type	drv_type;		//驱动类型,S3C2410或S3C2412
	struct s3c2410fb_hw	regs;			//s3c2410 lcd硬件寄存器

	unsigned int		palette_ready;	//调色板是否就绪标志位

	/* keep these registers in case we need to re-write palette */
	u32			palette_buffer[256];	//调色板缓冲区
	u32			pseudo_pal[16];			//伪颜色表
};
s3c2410fb_display结构体,关于LCD参数的描述,如分辨率,LCD类型,BPP等等

/* LCD description */
struct s3c2410fb_display {
	/* LCD type */
	unsigned type;

	/* Screen size */
	unsigned short width;
	unsigned short height;

	/* Screen info */
	unsigned short xres;
	unsigned short yres;
	unsigned short bpp;

	unsigned pixclock;			 /* pixclock in picoseconds */
	unsigned setclkval;			 /* clkval */
	unsigned short left_margin;  /* value in pixels (TFT) or HCLKs (STN) */
	unsigned short right_margin; /* value in pixels (TFT) or HCLKs (STN) */
	unsigned short hsync_len;    /* value in pixels (TFT) or HCLKs (STN) */
	unsigned short upper_margin; /* value in lines (TFT) or 0 (STN) */
	unsigned short lower_margin; /* value in lines (TFT) or 0 (STN) */
	unsigned short vsync_len;	 /* value in lines (TFT) or 0 (STN) */

	/* lcd configuration registers */
	unsigned long	lcdcon5;
};
对于TQ2440的液晶屏实例为tq2440_lcd_cfg,为方便查阅这里省略了其他分辨率的参数设置

/* LCD driver info */
static struct s3c2410fb_display tq2440_lcd_cfg __initdata = {
	.lcdcon5	= S3C2410_LCDCON5_FRM565 |
			  S3C2410_LCDCON5_INVVLINE |
			  S3C2410_LCDCON5_INVVFRAME |
			  S3C2410_LCDCON5_PWREN |
			  S3C2410_LCDCON5_HWSWP,
	.type		= S3C2410_LCDCON1_TFT,
	/* TQ2440的液晶是4.3寸的,分辨率是480*272 */
#elif defined(CONFIG_FB_S3C24X0_TFT480272)  /* config_EmbedSky_W43:CONFIG_FB_S3C24X0_TFT480272=y */
	.width		= 480,
	.height		= 272,

	.pixclock	= 40000,    /* HCLK 100 MHz, divisor 1 */
	.setclkval	= 0x4,
	.xres		= 480,
	.yres		= 272,
	.bpp		= 16,
	.left_margin	= 19,	/* for HFPD*/
	.right_margin	= 10,	/* for HBPD*/
	.hsync_len	= 30,		/* for HSPW*/
	.upper_margin	= 4,	/* for VFPD*/
	.lower_margin	= 2,	/* for VBPD*/
	.vsync_len	= 8,		/* for VSPW*/
};
s3c2410fb_mach_info结构体,它包括了s3c2410fb_display结构体

struct s3c2410fb_mach_info {
	struct s3c2410fb_display *displays;		//s3c2410fb_display结构体
	unsigned num_displays;					//displays的个数
	unsigned default_display;				//默认的default_display个数

	/* GPIOs */
	unsigned long	gpcup;					//GPC
	unsigned long	gpcup_mask;
	unsigned long	gpccon;
	unsigned long	gpccon_mask;
	unsigned long	gpdup;					//GPD
	unsigned long	gpdup_mask;
	unsigned long	gpdcon;
	unsigned long	gpdcon_mask;

	/* lpc3600 control register */
	unsigned long	lpcsel;
};
要理解s3c24xxfb_probe函数,首先必须理清上面几个结构体之间的关系。

  • 4
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值