《Linux驱动:s3c2440 lcd 驱动分析--终结篇》

发布者:Heavenly999最新更新时间:2024-07-09 来源: elecfans关键字:Linux驱动  s3c2440  lcd  驱动 手机看文章 扫描二维码
随时随地手机看文章

// HSPW: 一个HSYNC信号的时间宽度

fbinfo->var.left_margin     = S3C2410_LCDCON3_GET_HFPD(mregs->lcdcon3) + 1;

fbinfo->var.right_margin    = S3C2410_LCDCON3_GET_HBPD(mregs->lcdcon3) + 1;

fbinfo->var.hsync_len       = S3C2410_LCDCON4_GET_HSPW(mregs->lcdcon4) + 1;

4.2.3 其他参数设置

fbinfo->fbops           = &s3c2410fb_ops;

fbinfo->flags           = FBINFO_FLAG_DEFAULT;


// 设置调色板

fbinfo->pseudo_palette      = &info->pseudo_pal;


s3c2410fb_ops:

static struct fb_ops s3c2410fb_ops = {

    .owner      = THIS_MODULE,

    .fb_check_var   = s3c2410fb_check_var,

    .fb_set_par = s3c2410fb_set_par,

    .fb_blank   = s3c2410fb_blank,

    .fb_setcolreg   = s3c2410fb_setcolreg,

    .fb_fillrect    = cfb_fillrect,

    .fb_copyarea    = cfb_copyarea,

    .fb_imageblit   = cfb_imageblit,

};

4.2.4 硬件相关设置(相关寄存器和引脚)

/* Stop the video and unset ENVID if set */

// 设置LCD控制器的lcdcon1寄存器,第0位为0,先失能lcd等设置完其他参数后,需要开启LCD,再使能该位

info->regs.lcdcon1 &= ~S3C2410_LCDCON1_ENVID;

lcdcon1 = readl(S3C2410_LCDCON1);

writel(lcdcon1 & ~S3C2410_LCDCON1_ENVID, S3C2410_LCDCON1);


// 设置GPB0 低电平,即关闭LCD背光,后面需要开启背光

// add by thisway.diy@163.com, for eBlocks

s3c2410_gpio_setpin(S3C2410_GPB0, 0);   // back light control


// 设置调色板数据

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

    info->palette_buffer[i] = PALETTE_BUFF_CLEAR;


if (!request_mem_region((unsigned long)S3C24XX_VA_LCD, SZ_1M, 's3c2410-lcd')) {

    ret = -EBUSY;

    goto dealloc_fb;

}



dprintk('got LCD regionn');


// 设置LCD中断

ret = request_irq(irq, s3c2410fb_irq, IRQF_DISABLED, pdev->name, info);

if (ret) {

    dev_err(&pdev->dev, 'cannot get irq %d - err %dn', irq, ret);

    ret = -EBUSY;

    goto release_mem;

}


// 使能LCD clk 

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

if (!info->clk || IS_ERR(info->clk)) {

    printk(KERN_ERR 'failed to get lcd clock sourcen');

    ret = -ENOENT;

    goto release_irq;

}

clk_enable(info->clk);

dprintk('got and enabled clockn');


msleep(1);



/* Initialize video memory */

// 申请frame buff内存并初始化

ret = s3c2410fb_map_video_memory(info);

if (ret) {

    printk( KERN_ERR 'Failed to allocate video RAM: %dn', ret);

    ret = -ENOMEM;

    goto release_clock;

}

dprintk('got video memoryn');


// 根据s3c2440芯片手册和使用的屏的规格书设置相关寄存器和引脚

ret = s3c2410fb_init_registers(info);


ret = s3c2410fb_check_var(&fbinfo->var, fbinfo);

static int s3c2410fb_init_registers(struct s3c2410fb_info *fbi)

{

    unsigned long flags;


    /* Initialise LCD with values from haret */


    local_irq_save(flags);


    /* modify the gpio(s) with interrupts set (bjd) */

    // 根据s3c2440芯片手册设置

    // 设置GPC引脚上拉使能 mach_info->gpcup 0xffffffff

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

    // 设置GPC引脚为LCD功能 mach_info->gpccon 0xaaaaaaaa -> 1010 1010 1010 1010 1010 1010 1010 1010

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

    // 设置GPD引脚上拉使能  mach_info->gpdup  0xffffffff

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

    // 设置GPD引脚为LCD功能 mach_info->gpdcon 0xaaaaaaaa

    modify_gpio(S3C2410_GPDCON, mach_info->gpdcon, mach_info->gpdcon_mask);


    local_irq_restore(flags);


    // 根据s3c2440芯片手册设置

    // lcdcon1: S3C2410_LCDCON1_TFT16BPP | S3C2410_LCDCON1_TFT | S3C2410_LCDCON1_CLKVAL(0x04),

    writel(fbi->regs.lcdcon1, S3C2410_LCDCON1);

    // lcdcon2: S3C2410_LCDCON2_VBPD(1) | S3C2410_LCDCON2_LINEVAL(271) | S3C2410_LCDCON2_VFPD(1) | S3C2410_LCDCON2_VSPW(9) 

    writel(fbi->regs.lcdcon2, S3C2410_LCDCON2);

    // lcdcon3: S3C2410_LCDCON3_HBPD(1) |  S3C2410_LCDCON3_HOZVAL(479) |  S3C2410_LCDCON3_HFPD(1)

    writel(fbi->regs.lcdcon3, S3C2410_LCDCON3);

    // lcdcon4: S3C2410_LCDCON4_HSPW(40)

    writel(fbi->regs.lcdcon4, S3C2410_LCDCON4);

    // lcdcon5: S3C2410_LCDCON5_FRM565 | S3C2410_LCDCON5_INVVLINE | S3C2410_LCDCON5_INVVFRAME | S3C2410_LCDCON5_PWREN | S3C2410_LCDCON5_HWSWP,

    writel(fbi->regs.lcdcon5, S3C2410_LCDCON5);


    // 根据s3c2440芯片手册设置

    // 设置地址相关寄存器 LCDSADDR1、LCDSADDR2、LCDSADDR3

    s3c2410fb_set_lcdaddr(fbi);


    dprintk('LPCSEL    = 0x%08lxn', mach_info->lpcsel);

    writel(mach_info->lpcsel, S3C2410_LPCSEL);


    dprintk('replacing TPAL %08xn', readl(S3C2410_TPAL));

    // 不使用调色板

    /* ensure temporary palette disabled */

    writel(0x00, S3C2410_TPAL);



#if 0   

    /* ghcstop modified */

    s3c2410_gpio_cfgpin(S3C2410_GPC5, S3C2410_GPC5_OUTP); // lcd display enable/disable

    s3c2410_gpio_cfgpin(S3C2410_GPB1, S3C2410_GPB1_OUTP); // back light control

    s3c2410_gpio_cfgpin(S3C2410_GPH6, S3C2410_GPH6_OUTP); 


    s3c2410_gpio_pullup(S3C2410_GPC5, 0); 

    s3c2410_gpio_pullup(S3C2410_GPB1, 0);

    s3c2410_gpio_pullup(S3C2410_GPH6, 0);


    s3c2410_gpio_setpin(S3C2410_GPC5, 1);

    s3c2410_gpio_setpin(S3C2410_GPH6, 1); 

    s3c2410_gpio_setpin(S3C2410_GPB1, 1);

#else

    /* thisway.diy@163.com modify again, for eBlocks */

    s3c2410_gpio_cfgpin(S3C2410_GPB0, S3C2410_GPB0_OUTP); // back light control


    s3c2410_gpio_pullup(S3C2410_GPB0, 0); 


    s3c2410_gpio_setpin(S3C2410_GPB0, 1);   // back light control, enable

#endif


    /* probably not required */

    msleep(10);     


    // 使能lcd

    /* Enable video by setting the ENVID bit to 1 */

    fbi->regs.lcdcon1 |= S3C2410_LCDCON1_ENVID;

    writel(fbi->regs.lcdcon1, S3C2410_LCDCON1);


    // add by thisway.diy@163.com, for eBlocks

    // 开启背光

    s3c2410_gpio_setpin(S3C2410_GPB0, 1);   // back light control


    return 0;

}

五,fbmem字符设备驱动

5.1 驱动加载并初始化

编译进内核,加载

linux-2.6.22.6/drivers/video/Makefile


fb-y                              := fbmem.o fbmon.o fbcmap.o fbsysfs.o

                                     modedb.o fbcvt.o

fb-objs                           := $(fb-y)

linux-2.6.22.6/drivers/video/fbmem.c


subsys_initcall(fbmem_init);

static int __init

fbmem_init(void)

{

    create_proc_read_entry('fb', 0, NULL, fbmem_read_proc, NULL);


    // 注册字符设备

    if (register_chrdev(FB_MAJOR,'fb',&fb_fops))

        printk('unable to get major %d for fb devsn', FB_MAJOR);


    // 创建设备类 /sys/class/graphics

    fb_class = class_create(THIS_MODULE, 'graphics');

    if (IS_ERR(fb_class)) {

        printk(KERN_WARNING 'Unable to create fb class; errno = %ldn', PTR_ERR(fb_class));

        fb_class = NULL;

    }

    return 0;

}

5.2 register_framebuffer

int

register_framebuffer(struct fb_info *fb_info)

{

    int i;

    struct fb_event event;

    struct fb_videomode mode;


    // 最多支持32个fb设备

    if (num_registered_fb == FB_MAX)

        return -ENXIO;

    num_registered_fb++;

    // 从registered_fb中找到一项空的位置,存放本次fb。下标作为次设备号,创建设备节点,以供应用程序使用

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

        if (!registered_fb[i])

            break;

    fb_info->node = i;


    // 创建设备 节点。/dev/fb%d

    fb_info->dev = device_create(fb_class, fb_info->device,

                     MKDEV(FB_MAJOR, i), 'fb%d', i);

    if (IS_ERR(fb_info->dev)) {

        /* Not fatal */

        printk(KERN_WARNING 'Unable to create device for framebuffer %d; errno = %ldn', i, PTR_ERR(fb_info->dev));

        fb_info->dev = NULL;

    } else

        fb_init_device(fb_info);


    if (fb_info->pixmap.addr == NULL) {

        fb_info->pixmap.addr = kmalloc(FBPIXMAPSIZE, GFP_KERNEL);

        if (fb_info->pixmap.addr) {

            fb_info->pixmap.size = FBPIXMAPSIZE;

            fb_info->pixmap.buf_align = 1;

            fb_info->pixmap.scan_align = 1;

            fb_info->pixmap.access_align = 32;

            fb_info->pixmap.flags = FB_PIXMAP_DEFAULT;

        }

    }   

    fb_info->pixmap.offset = 0;


    if (!fb_info->pixmap.blit_x)

        fb_info->pixmap.blit_x = ~(u32)0;


    if (!fb_info->pixmap.blit_y)

        fb_info->pixmap.blit_y = ~(u32)0;


    if (!fb_info->modelist.prev || !fb_info->modelist.next)

        INIT_LIST_HEAD(&fb_info->modelist);


    fb_var_to_videomode(&mode, &fb_info->var);

    fb_add_videomode(&mode, &fb_info->modelist);

    registered_fb[i] = fb_info;


    event.info = fb_info;

[1] [2] [3] [4]
关键字:Linux驱动  s3c2440  lcd  驱动 引用地址:《Linux驱动:s3c2440 lcd 驱动分析--终结篇》

上一篇:s3c2440裸机-时钟编程-1-2440时钟体系介绍
下一篇:《Linux驱动:s3c2440 lcd 驱动分析》

小广播
最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

厂商技术中心

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

 
机器人开发圈

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2026 EEWORLD.com.cn, Inc. All rights reserved