s3c2410 lcd驱动分析(1)

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->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有三个是固定的,主要要实现两个函数。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值