LCD驱动IC的构成及作用是啥?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LCD驱动IC的构成及作用是啥?相关的知识,希望对你有一定的参考价值。

LCD驱动IC的原理液晶显示器讯号扫描方式为一次一列,并且逐列而下。Gate Driver IC连结至晶体管之Gate端,负责每一列晶体管的开关,扫描时一次打开一整列的晶体管。当晶体管打开(ON)时,Source Driver IC才能够逐行将控制亮度、灰阶、色彩的控制电压透过晶体管Source端、Drain端形成的通道进入Panel的画素中。因为Gate Driver IC负责每列晶体管的开关,所以又称为Row Driver或Scan Driver。当Gate Driver逐列动作时,Source Driver IC负责在每一列中将数据电压逐行输入,因此又称为Column Driver或Data Driver。

大尺寸LCD驱动IC的特点

第一,高电压工艺。模拟电路中电压越高,驱动能力越强,因此大尺寸LCD驱动IC采用高电压制造工艺,通常Source Driver IC为10~12V, Gate Driver IC更高,达40V。

第二,运行频率高。液晶显示器的分辨率越来越高,这就意味着扫描列数的增加, Gate Driver IC必须不断提高开关频率, Source Driver IC必须不断提高扫描频率。

第三,封装工艺特殊。LCD驱动IC通常绑定在LCD面板上,因此厚度必须尽可能地薄,通常采用高成本的TCP封装。还有特别追求薄的,采用COG封装,再有就是目前正在兴起的COF封装。

第四,管脚数特别多。Gate Driver IC最少256脚, Source Driver IC最少384脚。

第五,单一型号出货量特别大。驱动IC 单月平均出货量高达1.5亿片,而其中平均每个型号的出货量达差不多在300万片左右。

LCD 的构造是在两片平行的玻璃当中放置液态的晶体,两片玻璃中间有许多垂直和水平的细小电线,透过通电与否来控制杆状水晶分子改变方向,将光线折射出来产生画面。

参考技术A LCD驱动IC的原理液晶显示器讯号扫描方式为一次一列,并且逐列而下。Gate Driver IC连结至晶体管之Gate端,负责每一列晶体管的开关,扫描时一次打开一整列的晶体管。当晶体管打开(ON)时,Source Driver IC才能够逐行将控制亮度、灰阶、色彩的控制电压透过晶体管Source端、Drain端形成的通道进入Panel的画素中。因为Gate Driver IC负责每列晶体管的开关,所以又称为Row Driver或Scan Driver。当Gate Driver逐列动作时,Source Driver IC负责在每一列中将数据电压逐行输入,因此又称为Column Driver或Data Driver。
大尺寸LCD驱动IC的特点第一,高电压工艺。模拟电路中电压越高,驱动能力越强,因此大尺寸LCD驱动IC采用高电压制造工艺,通常Source Driver IC为10~12V, Gate Driver IC更高,达40V。

第二,运行频率高。液晶显示器的分辨率越来越高,这就意味着扫描列数的增加, Gate Driver IC必须不断提高开关频率, Source Driver IC必须不断提高扫描频率。

第三,封装工艺特殊。LCD驱动IC通常绑定在LCD面板上,因此厚度必须尽可能地薄,通常采用高成本的TCP封装。还有特别追求薄的,采用COG封装,再有就是目前正在兴起的COF封装。

第四,管脚数特别多。Gate Driver IC最少256脚, Source Driver IC最少384脚。

第五,单一型号出货量特别大。驱动IC 单月平均出货量高达1.5亿片,而其中平均每个型号的出货量达差不多在300万片左右。

Linux的LCD驱动分析及移植

测试平台

宿主机平台:Ubuntu 12.04.4 LTS

目标机:Easy-ARM IMX283

目标机内核:Linux 2.6.35.3

 

LCD驱动分析

LCD屏的驱动总体上分成两块,一块是GUI显示输出驱动;一块是触摸驱动(该部分单独一节另外描述)。

LCD驱动概念

LCD是Liquid Crystal Display的简称,也就是经常所说的液晶显示器。LCD能够支持彩色图像的显示和视频的播放,是一种非常重要的输出设备。如果我们的系统要用GUI(图形界面接口),比如minigui,MicroWindows。这时LCD设备驱动程序就应该编写成frambuffer接口,而不是编写成仅仅操作底层的LCD控制器接口。

framebuffer是Linux系统为显示设备提供的一个接口,它将显示缓冲区抽象,屏蔽图像硬件的底层差异,允许上层应用程序在图形模式下直接对显示缓冲区进行操作。framebuffer又叫帧缓冲,是Linux为操作显示设备提供的一个用户接口。用户应用程序可以通过framebuffer透明地访问不同类型的显示设备。从这个方面来说,framebuffer是硬件设备显示缓冲区的抽象。Linux抽象出framebuffer这个帧缓冲区可以供用户应用程序直接读写,通过更改framebuffer中的内容,就可以立刻显示在LCD显示屏上。

framebuffer是一个标准的字符设备,主设备号是29,次设备号根据缓冲区的数目而定。framebuffer对应/dev/fb%d设备文件。根据显卡的多少,设备文件可能是/dev/fb0、/dev/fb1等。缓冲区设备也是一种普通的内存设备,可以直接对其进行读写。对用户程序而言,它和/dev下面的其他设备没有什么区别,用户可以把frameBuffer看成一块内存,既可以写,又可以读。显示器将根据内存数据显示对应的图像界面。这一切都由LCD控制器和响应的驱动程序来完成。

 

LCD驱动框架分析

总体上是一个平台设备驱动与字符驱动的组合;

先从LCD的设备 dev/fb* 是怎么实现的来进行追溯;

1.开发板启动,进行设备注册;

在  arch/arm/mach-mx28/device.c  设备注册文件中,注册LCD的fd平台设备 “mxs-fb”

// mxs-fb平台设备资源定义
static
struct resource framebuffer_resource[] = .flags = IORESOURCE_MEM, .start = LCDIF_PHYS_ADDR, .end = LCDIF_PHYS_ADDR + 0x2000 - 1, , .flags = IORESOURCE_IRQ, .start = IRQ_LCDIF, .end = IRQ_LCDIF, , ;
// mxs-fb平台设备用户数据,包含显示屏的分辨率等信息
static struct mxs_platform_fb_data mxs_framebuffer_pdata = .list = LIST_HEAD_INIT(mxs_framebuffer_pdata.list), ; static void __init mx28_init_lcdif(void) struct platform_device *pdev; pdev = mxs_get_device("mxs-fb", 0); if (pdev == NULL || IS_ERR(pdev)) return; pdev->resource = framebuffer_resource; pdev->num_resources = ARRAY_SIZE(framebuffer_resource); pdev->dev.platform_data = &mxs_framebuffer_pdata; mxs_add_device(pdev, 3);

2.接下来是 platform_driver   mxsfb_driver 的注册,匹配之后触发 mxsfb_probe 函数执行以下操作:

进行相关硬件初始化和 framebuffer 设置;

register_framebuffer()  注册 LCD 屏的 fd 设备;
 
LCD的驱动包含:
drivers/video/mxs/lcd_43wvf1g.c  //
drivers/video/mxs/lcdif.c       //
drivers/video/mxs/mxsfb.c      //

平台设备驱动 platform_driver 注册  drivers/video/mxs/mxsfb.c 

static struct platform_driver mxsfb_driver = 
    .probe = mxsfb_probe,
    .remove = mxsfb_remove,
    .suspend = mxsfb_suspend,
    .resume = mxsfb_resume,
    .driver = 
           .name = "mxs-fb",    // 与启动时的平台设备注册的 platform_device 名称相同
           .owner = THIS_MODULE,
           ,
;

static int __init mxsfb_init(void)

    return platform_driver_register(&mxsfb_driver);

驱动安装时与平台设备匹配之后触发 mxsfb_probe 函数,这个时核心。

static int __devinit mxsfb_probe(struct platform_device *pdev)

    int ret = 0;
    struct mxs_fb_data *data;
    struct resource *res;
    struct fb_info *info;
    struct mxs_platform_fb_data *pdata = pdev->dev.platform_data;
    struct mxs_platform_fb_entry *pentry = NULL;

    mydbg("\n");
    if (pdata == NULL) 
        ret = -ENODEV;
        goto out;
    

    if (default_panel_name) 
        mydbg("default_panel_name=%s\n",default_panel_name);
        pentry = (void *)mxs_lcd_iterate_pdata(pdata,
                               get_matching_pentry_by_name,
                               default_panel_name);
        if (pentry) 
            mxs_lcd_move_pentry_up(pentry, pdata);
            pdata->cur = pentry;
        
    
    if (!default_panel_name || !pentry) 
        mydbg("\n");
        pentry = pdata->cur;
    
    if (!pentry || !pentry->init_panel || !pentry->run_panel ||
        !pentry->release_panel) 
        mydbg("\n");
        ret = -EINVAL;
        goto out;
    

    data =
        (struct mxs_fb_data *)framebuffer_alloc(sizeof(struct mxs_fb_data) +
                            sizeof(u32) * 256 -
                            sizeof(struct fb_info),
                            &pdev->dev);
    if (data == NULL) 
        ret = -ENOMEM;
        goto out;
    

    cdata = data;
    data->dev = &pdev->dev;
    data->pdata = pdata;
    platform_set_drvdata(pdev, data);
    info = &data->info;

    dev_dbg(&pdev->dev, "resolution %dx%d, bpp %d\n", pentry->x_res,
        pentry->y_res, pentry->bpp);

    mxs_lcd_iterate_pdata(pdata, get_max_memsize, data);

    data->map_size = PAGE_ALIGN(data->mem_size) * NUM_SCREENS;
    dev_dbg(&pdev->dev, "memory to allocate: %d\n", data->map_size);

    data->virt_start = dma_alloc_writecombine(&pdev->dev,
                          data->map_size,
                          &data->phys_start,
                          GFP_KERNEL);

    if (data->virt_start == NULL) 
        ret = -ENOMEM;
        goto out_dma;
    
    dev_dbg(&pdev->dev, "allocated at %p:0x%x\n", data->virt_start,
        data->phys_start);
    mutex_init(&data->blank_mutex);
    INIT_WORK(&data->work, mxsfb_task);
    data->state = F_ENABLE;

    mxsfb_default.bits_per_pixel = pentry->bpp;
    /* NB: rotated */
    mxsfb_default.xres = pentry->y_res;
    mxsfb_default.yres = pentry->x_res;
    mxsfb_default.xres_virtual = pentry->y_res;
    mxsfb_default.yres_virtual = data->map_size /
        (pentry->y_res * pentry->bpp / 8);
    if (mxsfb_default.yres_virtual >= mxsfb_default.yres * 2)
        mxsfb_default.yres_virtual = mxsfb_default.yres * 2;
    else
        mxsfb_default.yres_virtual = mxsfb_default.yres;

    mxsfb_fix.smem_start = data->phys_start;
    mxsfb_fix.smem_len = pentry->y_res * pentry->x_res * pentry->bpp / 8;
    mxsfb_fix.ypanstep = 1;

    switch (pentry->bpp) 
    case 32:
    case 24:
        mxsfb_default.red.offset = 16;
        mxsfb_default.red.length = 8;
        mxsfb_default.green.offset = 8;
        mxsfb_default.green.length = 8;
        mxsfb_default.blue.offset = 0;
        mxsfb_default.blue.length = 8;
        break;

    case 16:
#if 0
        mxsfb_default.red.offset = 11;
        mxsfb_default.red.length = 5;
        mxsfb_default.green.offset = 5;
        mxsfb_default.green.length = 6;
        mxsfb_default.blue.offset = 0;
        mxsfb_default.blue.length = 5;
        break;
#else
        mxsfb_default.red.offset = 0 ;
        mxsfb_default.red.length = 5;
        mxsfb_default.green.offset = 5;
        mxsfb_default.green.length = 6;
        mxsfb_default.blue.offset = 11;
        mxsfb_default.blue.length = 5;
        break;
#endif
    default:
        dev_err(&pdev->dev, "unsupported bitwidth %d\n", pentry->bpp);
        ret = -EINVAL;
        goto out_dma;
    

    info->screen_base = data->virt_start;
    info->fbops = &mxsfb_ops;
    info->var = mxsfb_default;
    info->fix = mxsfb_fix;
    info->pseudo_palette = &data->par;
    data->par = NULL;
    info->flags = FBINFO_FLAG_DEFAULT;

    init_waitqueue_head(&data->vsync_wait_q);
    data->vsync_count = 0;

    res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
    if (res == NULL) 
        dev_err(&pdev->dev, "cannot get IRQ resource\n");
        ret = -ENODEV;
        goto out_dma;
    
    data->regbase = (unsigned long)IO_ADDRESS(res->start);

    res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
    if (res == NULL) 
        dev_err(&pdev->dev, "cannot get IRQ resource\n");
        ret = -ENODEV;
        goto out_dma;
    
    data->irq = res->start;

    mxsfb_check_var(&info->var, info);

    ret = fb_alloc_cmap(&info->cmap, 256, 0);
    if (ret)
        goto out_cmap;

    mxsfb_set_par(info);

    mxs_init_lcdif();
    ret = pentry->init_panel(data->dev, data->phys_start,
                 mxsfb_fix.smem_len, pentry);
    if (ret) 
        dev_err(&pdev->dev, "cannot initialize LCD panel\n");
        goto out_panel;
    
    dev_dbg(&pdev->dev, "LCD panel initialized\n");
    init_timings(data); // not effect dotclk mode

    ret = request_irq(data->irq, lcd_irq_handler, 0, "fb_irq", data);
    if (ret) 
        dev_err(&pdev->dev, "request_irq (%d) failed with error %d\n",
            data->irq, ret);
        goto out_panel;
    
    ret = register_framebuffer(info);    // 注册fb_info
    if (ret)
        goto out_irq;

    pentry->run_panel();
    /* REVISIT: temporary workaround for MX23EVK */
    mxsfb_disable_controller(data);
    mxsfb_enable_controller(data);
    data->cur_phys = data->phys_start;
    dev_dbg(&pdev->dev, "LCD running now\n");

#ifdef CONFIG_CPU_FREQ
    mxsfb_nb.fb_data = data;
    cpufreq_register_notifier(&mxsfb_nb.nb, CPUFREQ_TRANSITION_NOTIFIER);
#endif /* CONFIG_CPU_FREQ */

    goto out;

out_irq:
    free_irq(data->irq, data);
out_panel:
    fb_dealloc_cmap(&info->cmap);
out_cmap:
    dma_free_writecombine(&pdev->dev, data->map_size, data->virt_start,
                  data->phys_start);
out_dma:
    kfree(data);
out:
    return ret;

 

待续.....

 

以上是关于LCD驱动IC的构成及作用是啥?的主要内容,如果未能解决你的问题,请参考以下文章

什么是LCD驱动

VK1024B SOP16 LCD液晶段码屏显示驱动IC/LCD驱动芯片1621更少脚位 原厂FAE技术支持

LCD是怎么驱动的

驱动段码液晶屏常用哪些芯片

Linux的LCD驱动分析及移植

高通LCD的pwm背光驱动