您的位置:首页 > Web前端

s3c2410 lcd驱动分析(1)

2011-12-26 20:24 477 查看
s3c2410fb.c是平台通用的lcd驱动

platform_driver_register(&s3c2410fb_driver);用平台资源注册

    static struct platform_driver s3c2410fb_driver = {

    .probe        = s3c2410fb_probe,--------》

    .remove        = __devexit_p(s3c2410fb_remove),--------》

    .suspend    = s3c2410fb_suspend,

    .resume        = s3c2410fb_resume,

    .driver        = {

        .name    = "s3c2410-lcd",

        .owner    = THIS_MODULE,

    },

};

-------------------------------------------------------------

static int __devinit s3c24xxfb_probe(struct platform_device *pdev,enum s3c_drv_type drv_type)

    mach_info = pdev->dev.platform_data;//获得mach_info结构体s3c2410fb_mach_info结构体的资源在mach-smdk2410中添加,通过            

                                                                                 函数注册(void __init s3c24xx_fb_set_platdata(struct s3c2410fb_mach_info *pd))

    if (mach_info->default_display >= mach_info->num_displays)//判断设置的display值

    display = mach_info->displays + mach_info->default_display;//不明白为什么这里的偏移有什么鬼用

    irq = platform_get_irq(pdev, 0);/*获得irq资源*/其实就是调用platform_get_resource,封装成找irq资源

    fbinfo = framebuffer_alloc(sizeof(struct s3c2410fb_info), &pdev->dev);/*分配空间*/

    platform_set_drvdata(pdev, fbinfo);/*把fbinfo放到pdev下面的私有数据

    info = fbinfo->par;//将fb_info的私有数据指向info结构体,在函数中有用

    info->dev = &pdev->dev;//就是将设备的device结构体放入s3c2410fb_info结构体中

    

    res = platform_get_resource(pdev, IORESOURCE_MEM, 0);/*获得寄存器的地址资源*/

    size = (res->end - res->start) + 1;/*计算资源大小*/

    info->mem = request_mem_region(res->start, size, pdev->name);/*申请i/o资源的空间,i/o资源在使用前要申请,再映射才能访问,

                            据别人说这样的好处是访问资源时只要加偏移量

    info->io = ioremap(res->start, size);/*映射寄存器的地址*/

    //计算irq的基地址

    info->irq_base = info->io + ((drv_type == DRV_S3C2412) ? S3C2412_LCDINTBASE : S3C2410_LCDINTBASE);

    lcdcon1 = readl(info->io + S3C2410_LCDCON1);//读取lcdcon1寄存器的值

    writel(lcdcon1 & ~S3C2410_LCDCON1_ENVID, info->io + S3C2410_LCDCON1);/*往第一个寄存器写入数据,使能输出和控制信号

    fbinfo->fix.type        = FB_TYPE_PACKED_PIXELS;

    fbinfo->fix.type_aux        = 0;

    fbinfo->fix.xpanstep        = 0;

    fbinfo->fix.ypanstep        = 0;

    fbinfo->fix.ywrapstep        = 0;

    fbinfo->fix.accel        = FB_ACCEL_NONE;

    fbinfo->var.nonstd        = 0;

    fbinfo->var.activate        = FB_ACTIVATE_NOW;

    fbinfo->var.accel_flags     = 0;

    fbinfo->var.vmode        = FB_VMODE_NONINTERLACED;这几行设置一些看不懂的参数,一般照抄就行

    

    fbinfo->fbops            = &s3c2410fb_ops;//重要的操作函数

    fbinfo->flags            = FBINFO_FLAG_DEFAULT;//不知干什么的标志

    fbinfo->pseudo_palette      = &info->pseudo_pal;//调色板

    for (i = 0; i < 256; i++)

        info->palette_buffer[i] = PALETTE_BUFF_CLEAR;//清空调色板

    ret = request_irq(irq, s3c2410fb_irq, IRQF_DISABLED, pdev->name, info);//申请中断

        static irqreturn_t s3c2410fb_irq(int irq, void *dev_id)//不明白中断怎么产生,一般都没有用到中断

        

    info->clk = clk_get(NULL, "lcd");

    for (i = 0; i < mach_info->num_displays; i++) {

        unsigned long smem_len = mach_info->displays[i].xres;

        smem_len *= mach_info->displays[i].yres;

        smem_len *= mach_info->displays[i].bpp;

        smem_len >>= 3;

        if (fbinfo->fix.smem_len < smem_len)

            fbinfo->fix.smem_len = smem_len;

    }计算最大的frame buffer 长度

    ret = s3c2410fb_map_video_memory(fbinfo);/*设置LCD的buffer,包括虚拟地址,物理地址*/

            info->screen_base = dma_alloc_writecombine(fbi->dev, map_size,&map_dma, GFP_KERNEL);//分配一段内存用来做frame         

                        //buffer,在这里有一个cache数据一致性的问题,可以看另外的一篇文章

                info->screen_base    : 内存的虚拟起始地址,在内核要用此地址来操作所分配的内存

                fbi->dev      : 可以平台初始化里指定,主要是用到dma_mask之类参数,可参考framebuffer

                map_size      : 实际分配大小,传入dma_map_size即可

                &map_dma: 返回的内存物理地址,dma就可以用。

            info->fix.smem_start = map_dma;//设置物理地址

    fbinfo->var.xres = display->xres;

    fbinfo->var.yres = display->yres;

    fbinfo->var.bits_per_pixel = display->bpp;//这里设置可变的参数,宽,高,bpp(每像素多少位)

    s3c2410fb_init_registers(fbinfo);//初始化gpio端口

        struct s3c2410fb_info *fbi = info->par;//在前面已经将他们的地址复制了

        struct s3c2410fb_mach_info *mach_info = fbi->dev->platform_data;//前面讲info->dev = &pdev->dev中赋值

        modify_gpio(S3C2410_GPCUP,  mach_info->gpcup,  mach_info->gpcup_mask);

        modify_gpio(S3C2410_GPCCON, mach_info->gpccon, mach_info->gpccon_mask);

        modify_gpio(S3C2410_GPDUP,  mach_info->gpdup,  mach_info->gpdup_mask);

        modify_gpio(S3C2410_GPDCON, mach_info->gpdcon, mach_info->gpdcon_mask);设置gpio管脚

        writel(mach_info->lpcsel, lpcsel);//往LPCSEL写值

        writel(0x00, tpal);//往TPAL寄存器写值

    s3c2410fb_check_var(&fbinfo->var, fbinfo);//用来设置参数,在ioctl中也会调用到这个函数

        struct s3c2410fb_display *default_display = mach_info->displays +mach_info->default_display;//默认的display结构体

        int type = default_display->type;//lcd的类型

        if (var->yres == default_display->yres &&var->xres == default_display->xres &&var->bits_per_pixel == default_display->bpp)

            display = default_display;//使用默认的

        else

            for (i = 0; i < mach_info->num_displays; i++)

                if (type == mach_info->displays[i].type &&

                    var->yres == mach_info->displays[i].yres &&

                    var->xres == mach_info->
4000
displays[i].xres &&

                    var->bits_per_pixel == mach_info->displays[i].bpp) {

                    display = mach_info->displays + i;//使用设定的

                    break;

                }

        //it is always the size as the display

        var->xres_virtual = display->xres;

        var->yres_virtual = display->yres;

        var->height = display->height;

        var->width = display->width;

        

        /* copy lcd settings 都是寄存器里面需要设置的值

        var->pixclock = display->pixclock;//时钟

        var->left_margin = display->left_margin;//左边的延迟

        var->right_margin = display->right_margin;//右边的延迟

        var->upper_margin = display->upper_margin;//上面的延迟

        var->lower_margin = display->lower_margin;//下面的延迟

        var->vsync_len = display->vsync_len;//垂直方向的长度

        var->hsync_len = display->hsync_len;//水平方向的长度

        fbi->regs.lcdcon5 = display->lcdcon5;//lcdcon5寄存器的值

        fbi->regs.lcdcon1 = display->type;//设置lcdcon1的值,就是设置lcd的类型

        switch (var->bits_per_pixel)//这个switch里面就是更具bits_per_pixel的值设定红,绿,蓝的位长和偏移

    ret = s3c2410fb_cpufreq_register(info);//这里没用,没有定义

    ret = register_framebuffer(fbinfo);//在fb这个驱动架构中注册设备的函数,就是将fb_info结构体添加到fb_info的数组中,并设定了次设备号

    
    ret = device_create_file(&pdev->dev, &dev_attr_debug);//创建一个设备文件

在probe函数里面就是这些初始化的内容,对于lcd的驱动就是设置fb_info结构体的参数,包括:fb_var_screeninfo,fb_fix_screeninfo,设置寄存器的值,fb_ops几个方面的值。

在fb_ops有三个是固定的,主要要实现两个函数。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息