Table of Contents
2.2、平台驱动platform_driver (三星自带 s3c-fb.c)(可以自行编写)
2.2.2、时间参数设置s3c_fb_set_rgb_timing
2.2.3、LCD固定参数设置s3c_fb_probe_win
2.3、平台设备(platform_device) mach-tiny4412.c
2.3.1、struct platform_device s5p_device_fimd0
一、驱动框架图
核心层是通用的,不需要做任何修改。驱动开发者只需要实现硬件驱动层。
1. 帧缓冲设备可以一个完整的子系统,主要由核心层的 fbmem.c 和硬件设备驱动层构成
2. 核心层代码 fbmem.c 向上提供了完整的字符设备操作接口,也就是实现注册字符设备,提供通用的open,read,write,ioctl,mmap 等接口;向下给硬件设备驱动层提供标准的驱动编程接口;
3. 在 Linux 系统中,一个硬件 LCD 控制器(显卡)抽象为一个 fb_info 结构,要实现一个 LCD 驱动谅是要实现这个结构,并且使用核心层提供的注册函数注册。
4. fb_info 中通过其中的 fb_ops 结构指针提供了实际硬件操作方法。
5. fb_info 中通过其中的 fb_var_screeninfo 结构和 fb_fix_screeninfo 结构提供了具体 lcd 屏基本信息。
6.注册: register_framebuffer
7. 注销: unregister_framebuffer
二、LCD驱动工作原理
2.1、驱动入口(内核自带 fbmem.c)
linux/drivers/video/fbmem.c
static int __init fbmem_init(void)
{if (register_chrdev(FB_MAJOR,"fb",&fb_fops)) //FB_MAJOR 29
printk("unable to get major %d for fb devs\n", FB_MAJOR);、、、、、、、、、
return 0;
}static const struct file_operations fb_fops = {
.owner = THIS_MODULE,
.read = fb_read,
.write = fb_write,
.unlocked_ioctl = fb_ioctl,
、、、、、、、、、、、、、、、
.mmap = fb_mmap,
、、、、、、、、、、、、
};
2.2、平台驱动platform_driver (三星自带 s3c-fb.c)(可以自行编写)
2.2.1、 s3c_fb_probe函数
linux/drivers/video/s3c-fb.c
static struct platform_driver s3c_fb_driver = {
.probe = s3c_fb_probe,
、、、、、、
};static int __devinit s3c_fb_probe(struct platform_device *pdev)
{
、、、、、、、、、、、、、、、
pd = pdev->dev.platform_data; //获取平台数据
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); //得到内存资源
sfb->regs = devm_request_and_ioremap(dev, res);
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); //得到中断资源
/* setup gpio and output polarity controls */
pd->setup_gpio(); //gpio初始化
writel(pd->vidcon1, sfb->regs + VIDCON1);
s3c_fb_set_rgb_timing(sfb); //时间参数设置
ret = s3c_fb_probe_win(sfb, win, fbdrv->win[win], &sfb->windows[win]); //屏幕固定参数设置,显存设置,注册LCD
}
2.2.2、时间参数设置s3c_fb_set_rgb_timing
static void s3c_fb_set_rgb_timing(struct s3c_fb *sfb)
{
、、、、、、、、、、data = VIDTCON0_VBPD(vmode->upper_margin - 1) |
VIDTCON0_VFPD(vmode->lower_margin - 1) |
VIDTCON0_VSPW(vmode->vsync_len - 1);
writel(data, regs + sfb->variant.vidtcon);data = VIDTCON1_HBPD(vmode->left_margin - 1) |
VIDTCON1_HFPD(vmode->right_margin - 1) |
VIDTCON1_HSPW(vmode->hsync_len - 1);
writel(data, regs + sfb->variant.vidtcon + 4);data = VIDTCON2_LINEVAL(vmode->yres - 1) |
VIDTCON2_HOZVAL(vmode->xres - 1) |
VIDTCON2_LINEVAL_E(vmode->yres - 1) |
VIDTCON2_HOZVAL_E(vmode->xres - 1);
writel(data, regs + sfb->variant.vidtcon + 8);
}
2.2.3、LCD固定参数设置s3c_fb_probe_win
tatic int __devinit s3c_fb_probe_win(struct s3c_fb *sfb, unsigned int win_no,
struct s3c_fb_win_variant *variant,
struct s3c_fb_win **res){
、、、、、、、、、、、、、、、、、、、、、、、
ret = s3c_fb_alloc_memory(sfb, win);
、、、、、、、、、、、、、、、
/* Set 8bpp or 8bpp and 1bit alpha */
win->palette.r.offset = 16;
win->palette.r.length = 8;
win->palette.g.offset = 8;
win->palette.g.length = 8;
win->palette.b.offset = 0;
win->palette.b.length = 8;
、、、、、、、、、、、、、、、、、、、fbinfo->var.width = windata->width;
fbinfo->var.height = windata->height;
fbinfo->fix.type = FB_TYPE_PACKED_PIXELS;
fbinfo->fix.accel = FB_ACCEL_NONE;
fbinfo->var.activate = FB_ACTIVATE_NOW;
fbinfo->var.vmode = FB_VMODE_NONINTERLACED;
fbinfo->var.bits_per_pixel = windata->default_bpp;
fbinfo->fbops = &s3c_fb_ops;
fbinfo->flags = FBINFO_FLAG_DEFAULT;
fbinfo->pseudo_palette = &win->pseudo_palette;/* prepare to actually start the framebuffer */
ret = s3c_fb_check_var(&fbinfo->var, fbinfo);
、、、、、、、、、、、、、、、s3c_fb_set_par(fbinfo);
/* run the check_var and set_par on our configuration. */
ret = register_framebuffer(fbinfo);
、、、、、、、、、、、、
return 0;
}
2.2.4、显存分配s3c_fb_alloc_memory
static int __devinit s3c_fb_alloc_memory(struct s3c_fb *sfb,
struct s3c_fb_win *win)
{
struct fb_info *fbi = win->fbinfo;
、、、、、、、、、、、、、、、、、
fbi->screen_base = dma_alloc_writecombine(sfb->dev, size,&map_dma, GFP_KERNEL);return 0;
}
2.3、平台设备(platform_device) mach-tiny4412.c
2.3.1、struct platform_device s5p_device_fimd0
linux/arch/arm/plat-samsung/devs.c
struct platform_device s5p_device_fimd0 = {
.name = "exynos4-fb",
.id = 0,
.num_resources = ARRAY_SIZE(s5p_fimd0_resource),
.resource = s5p_fimd0_resource,
.dev = {
.dma_mask = &samsung_device_dma_mask,
.coherent_dma_mask = DMA_BIT_MASK(32),
},
};void __init s5p_fimd0_set_platdata(struct s3c_fb_platdata *pd)
{//s5p_device_fimd0->dev->platform_data = smdk4x12_lcd0_pdata (smdk4x12_lcd0_pdata将下面解析)
s3c_set_platdata(pd, sizeof(struct s3c_fb_platdata), &s5p_device_fimd0);
}
2.3.2、平台资源struct resource
static struct resource s5p_fimd0_resource[] = {
[0] = DEFINE_RES_MEM(S5P_PA_FIMD0, SZ_32K),
[1] = DEFINE_RES_IRQ(IRQ_FIMD0_VSYNC),
[2] = DEFINE_RES_IRQ(IRQ_FIMD0_FIFO),
[3] = DEFINE_RES_IRQ(IRQ_FIMD0_SYSTEM),
};
2.3.3、平台数据platform_data
static struct s3c_fb_platdata smdk4x12_lcd0_pdata __initdata = {
.win[0] = &smdk4x12_fb_win0,
.win[1] = &smdk4x12_fb_win1,
.win[2] = &smdk4x12_fb_win2,
.win[3] = &smdk4x12_fb_win3,
.win[4] = &smdk4x12_fb_win4,
.vtiming = &smdk4x12_lcd_timing,
.vidcon0 = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB,//重要寄存器设置
.vidcon1 = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC,
.setup_gpio = exynos4_fimd0_gpio_setup_24bpp, //管脚设置函数
};static void __init smdk4x12_machine_init(void)
{、、、、、、、、、、、、、
tiny4412_fb_init_pdata(&smdk4x12_lcd0_pdata);
s5p_fimd0_set_platdata(&smdk4x12_lcd0_pdata); //设置platform_data成员为smdk4x12_lcd0_pdata
、、、、、、、、、、、、、、
}static void __init tiny4412_fb_init_pdata(struct s3c_fb_platdata *pd) {
、、、、、、、、、、、、、、、、、、、、、、、、、、、
lcd = tiny4412_get_lcd();、、、、、、、、、、、、、、、、、、
}struct s3cfb_lcd *tiny4412_get_lcd(void)
{
return tiny4412_lcd_config[lcd_idx].lcd;
}tiny4412_lcd_config[] = {
{ "S70", &wvga_s70, 1 },
、、、、、、、、、
};
2.3.4、屏幕参数设备信息(一般就是修改这里)
static struct s3cfb_lcd wvga_s70 = {
.width = 800,
.height = 480,
.p_width = 155,
.p_height = 93,
.bpp = 24,
.freq = 63,.timing = {
.h_fp = 80,
.h_bp = 36,
.h_sw = 10,
.v_fp = 22,
.v_fpe = 1,
.v_bp = 15,
.v_bpe = 1,
.v_sw = 8,
},
.polarity = {
.rise_vclk = 1,
.inv_hsync = 1,
.inv_vsync = 1,
.inv_vden = 0,
},
};
2.4、应用程序读写LCD解析
--------------------------------------------------------------
假设
app: open("/dev/fb0", ...) 主设备号: 29, 次设备号: 0
--------------------------------------------------------------
kernel:
fb_open
int fbidx = iminor(inode);
struct fb_info *info = = registered_fb[fbidx ];app: read()
---------------------------------------------------------------
kernel:
fb_read
int fbidx = iminor(inode);
struct fb_info *info = registered_fb[fbidx];
if (info->fbops->fb_read)
return info->fbops->fb_read(info, buf, count, ppos);
src = (u32 __iomem *) (info->screen_base + p);
dst = buffer;
*dst++ = fb_readl(src++);
copy_to_user(buf, buffer, c)