历史上的今天
返回首页

历史上的今天

今天是:2024年10月11日(星期五)

正在发生

2018年10月11日 | OK6410之LCD驱动

2018-10-11 来源:eefocus

lcd.c驱动源码:

#include "linux/module.h"  

#include "linux/kernel.h"  

#include "linux/errno.h"  

#include "linux/string.h"  

#include "linux/mm.h"  

#include "linux/slab.h"  

#include "linux/vmalloc.h"  

#include "linux/delay.h"  

#include "linux/interrupt.h"  

#include "asm/uaccess.h"  

#include "linux/fb.h"  

#include "linux/init.h"  

#include "linux/clk.h"  

#include "linux/dma-mapping.h"  

  

static struct fb_info *s3c_lcd_info;  

static u32 s3c_pseudo_palette[16];  

  

static volatile unsigned long *gpbcon;  

static volatile unsigned long *gpbdat;  

static volatile unsigned long *gpfcon;  

static volatile unsigned long *gpfdat;  

static volatile unsigned long *gpicon;  

static volatile unsigned long *gpjcon;  

  

static volatile unsigned long *mifpcon;  

static volatile unsigned long *spcon;  

  

struct s3c6410_lcd_regs {  

    unsigned long vidcon0;  

    unsigned long vidcon1;  

    unsigned long vidcon2;  

    unsigned long reserver1;  

    unsigned long vidtcon0;  

    unsigned long vidtcon1;  

    unsigned long vidtcon2;  

    unsigned long reserver2;  

    unsigned long wincon0;  

    unsigned long wincon1;  

    unsigned long wincon2;  

    unsigned long wincon3;  

    unsigned long wincon4;  

    unsigned long reserver3[3];  

    unsigned long vidosd0a;  

    unsigned long vidosd0b;  

    unsigned long vidosd0c;  

    unsigned long reserver4;  

    unsigned long vidosd1a;  

    unsigned long vidosd1b;  

    unsigned long vidosd1c;  

    unsigned long vidosd1d;  

    unsigned long vidosd2a;  

    unsigned long vidosd2b;  

    unsigned long vidosd2c;  

    unsigned long vidosd2d;  

    unsigned long vidosd3a;  

    unsigned long vidosd3b;  

    unsigned long vidosd3c;  

    unsigned long reserver5;  

    unsigned long vidosd4a;  

    unsigned long vidosd4b;  

    unsigned long vidosd4c;  

    unsigned long reserver6[5];  

    unsigned long vidw00add0b0;  

    unsigned long vidw00add0b1;  

    unsigned long vidw01add0b0;  

    unsigned long vidw01add0b1;  

    unsigned long vidw02add0;  

    unsigned long reserver7;  

    unsigned long vidw03add0;  

    unsigned long reserver8;  

    unsigned long vidw04add0;  

    unsigned long reserver9[3];  

    unsigned long vidw00add1b0;  

    unsigned long vidw00add1b1;  

};  

static inline unsigned int chan_to_field(unsigned int chan, struct fb_bitfield *bf)  

{  

    chan &= 0xffff;  

    chan >>= 16 - bf->length;  

    return chan << bf->offset;  

}  

  

static int s3c_fb_setcolreg(unsigned int regno, unsigned int red,  

                 unsigned int green, unsigned int blue,  

                 unsigned int transp, struct fb_info *info)  

{  

    unsigned int val;  

      

    if (regno > 16)  

        return 1;  

    u32 *pal = info->pseudo_palette;  

  

    // 用red,green,blue三原色构造出val   

    val  = chan_to_field(red,   &info->var.red);  

    val |= chan_to_field(green, &info->var.green);  

    val |= chan_to_field(blue,  &info->var.blue);  

      

    pal[regno] = val;  

    return 0;  

}  

  

static struct fb_ops s3c_fb_ops = {  

    .owner = THIS_MODULE,  

    .fb_setcolreg   = s3c_fb_setcolreg,  

    .fb_fillrect    = cfb_fillrect,  

    .fb_copyarea    = cfb_copyarea,  

    .fb_imageblit   = cfb_imageblit,  

};  

  

static struct s3c6410_lcd_regs * lcd_regs;  

  

static int s3c_lcd_init(void)  

{  

    struct clk *clk;  

    int hclk;  

    int clkval;  

      

    // 1. 分配fb_info   

    s3c_lcd_info = framebuffer_alloc(0, NULL);  

  

    // 2. 设置   

    // 2.1 设置固定的信息   

    strcpy(s3c_lcd_info->fix.id, "uplooking_lcd");  

  

    s3c_lcd_info->fix.smem_len    = 480*272*2;  

    s3c_lcd_info->fix.type        = FB_TYPE_PACKED_PIXELS;  

    s3c_lcd_info->fix.visual      = FB_VISUAL_TRUECOLOR;  

    s3c_lcd_info->fix.line_length = 480*2;  

      

    // 2.2 设置可变的信息   

    s3c_lcd_info->var.xres           = 480;  //分辨率

    s3c_lcd_info->var.yres           = 272;  

    s3c_lcd_info->var.xres_virtual   = 480;  //虚拟分辨率

    s3c_lcd_info->var.yres_virtual   = 272;  

    s3c_lcd_info->var.bits_per_pixel = 16;  

  

    s3c_lcd_info->var.red.length     = 5;  

    s3c_lcd_info->var.red.offset      = 11;  

  

    s3c_lcd_info->var.green.length    = 6;  

    s3c_lcd_info->var.green.offset     = 5;  

  

    s3c_lcd_info->var.blue.length     = 5;  

    s3c_lcd_info->var.blue.offset       = 0;  

  

    s3c_lcd_info->var.activate            = FB_ACTIVATE_NOW;  

  

    // 2.3 设置操作函数   

    s3c_lcd_info->fbops = &s3c_fb_ops;  

  

    // 2.4 设置其他信息   

    //s3c_lcd_info->screen_base = ;              // 显存的虚拟地址   

    s3c_lcd_info->screen_size = 480*272*2;  

    s3c_lcd_info->pseudo_palette = &s3c_pseudo_palette;  

  

    // 4. 硬件相关的操作   

    // 4.1 配置GPIO用于LCD   

    gpicon = ioremap(0x7F008100, 4);  

    *gpicon = 0xAAAAAAAA;  

  

    gpjcon = ioremap(0x7F008120, 4);  

    *gpjcon = 0xAAAAAAAA;  

  

    gpbcon = ioremap(0x7F008020, 4);  

    gpbdat = gpbcon + 1;  

  

    gpfcon = ioremap(0x7F0080A0, 4);  

    gpfdat = gpfcon + 1;  

  

    // 4.2 根据LCD的性能设置LCD控制器  

    // MIFPCON   

    mifpcon = ioremap(0x7410800C, 4);  

    *mifpcon &= ~(1<<3);  

  

    spcon = ioremap(0x7F0081A0, 4);  

    *spcon &= ~(3);  

    *spcon |= 1;  

  

    lcd_regs = ioremap(0x77100000, sizeof(struct s3c6410_lcd_regs));  

  

    clk = clk_get(NULL, "lcd");  

    clk_enable(clk);  // HCLK_GATE[3]设为1   

 

    // HCLK_GATE = ioremap(0x7E00F030, 4); 

    // *HCLK_GATE |= (1<<3); 

  

    // bit[13:6], CLKVAL_F,VCLK = Video Clock Source / (CLKVAL+1) 

    //                                 VCLK = 9000000 

    //                 CLKVAL_F = hclk/9000000 - 1 

    // bit[3:2], CLKSEL_F, 00 = HCLK 

    // bit[1], ENVID-使能LCD控制器的输出, 先设为0, 最后全部设置好了再设为1 

    clk = clk_get(NULL, "hclk");  

    hclk = clk_get_rate(clk);  

    clkval = hclk/9000000 - 1;  

    printk(KERN_INFO "hclk = %d, clkval = %d\n", hclk, clkval);  

    lcd_regs->vidcon0 = (0<<29)|(0<<26) | (0<<17) | (clkval << 6) | (1<<4);  

  

    // bit[7], 0-在VLCK下降沿读数据 

    // bit[6], HSYNC低脉冲有效    

    // bit[5], VSYNC低脉冲有效    

    // bit[4], VDEN高电平有效 

    lcd_regs->vidcon1 = (0<<7) | (1<<6) | (1<<5) | (0<<4);  

  

    // LCD手册P11 

    // tvp = 10, tvb = 2, tvf=2 

    lcd_regs->vidtcon0 = (2<<16) | (2<<8) | (10<<0);  //修改了 都加1  

    // LCD手册P11 

    // thp = 41, thb = 2, thf=2 

       

    lcd_regs->vidtcon1 = (1<<16) | (1<<8) | (40<<0);  

  

    lcd_regs->vidtcon2 = (271<<11) | (479<<0);  

  

    // 4.3 分配显存, 并告诉LCD控制器   

    s3c_lcd_info->screen_base = dma_alloc_writecombine(NULL, s3c_lcd_info->screen_size,

                                                                                               &s3c_lcd_info->fix.smem_start, GFP_KERNEL);  

  

    // bit[17],BSWP = 0, bit[16],HWSWP = 0  

    // bit[5:2],BPPMODE_F, 0b1011, 24bpp 

    // bit[0], ENWIN_F, 0-先不使能 

       

    lcd_regs->wincon0 &= ~(0xf << 2);  

    //lcd_regs->wincon0 |= (0xb<<2);    // unpacked 24 BPP (non-palletized R:8-G:8-B:8 )   

    lcd_regs->wincon0 |= (0x5<<2);    

#define LeftTopX     0  

#define LeftTopY     0  

#define RightBotX   479  

#define RightBotY   271  

  

    lcd_regs->vidosd0a = (LeftTopX<<11) | (LeftTopY << 0);  

    lcd_regs->vidosd0b = (RightBotX<<11) | (RightBotY << 0);  

    //lcd_regs->vidosd0c = 480*272/2;  

    lcd_regs->vidosd0c = 480*272;  

  

    lcd_regs->vidw00add0b0 = s3c_lcd_info->fix.smem_start;  

    lcd_regs->vidw00add1b0 = (s3c_lcd_info->fix.smem_start + s3c_lcd_info->fix.smem_len) & 0xffffff;         

    // 4.4 使能   

    lcd_regs->vidcon0 |= (3);        // 使能LCD控制器输出信号   

    lcd_regs->wincon0 |= (1<<0); // 使能窗口0   

          

    // 3. 注册   

    register_framebuffer(s3c_lcd_info);  

  

    return 0;  

}  

  

static void s3c_lcd_exit(void)  

{  

    struct clk *clk;  

      

    unregister_framebuffer(s3c_lcd_info);  

  

    lcd_regs->vidcon0 &= ~(1<<1); // 禁止LCD控制器输出信号   

    lcd_regs->wincon0 &= ~(1<<0); // 禁止窗口0   

  

    dma_free_writecombine(NULL, s3c_lcd_info->screen_size, s3c_lcd_info->screen_base, 

                                             s3c_lcd_info->fix.smem_start);  

  

    clk = clk_get(NULL, "lcd");  

    clk_disable(clk);  // HCLK_GATE[3]设为0   

  

    iounmap(lcd_regs);  

    iounmap(gpbcon);  

    iounmap(gpfcon);  

    iounmap(gpicon);  

    iounmap(gpjcon);  

    iounmap(mifpcon);  

    iounmap(spcon);  

  

    framebuffer_release(s3c_lcd_info);  

}  

  

module_init(s3c_lcd_init);  

module_exit(s3c_lcd_exit);  

  

MODULE_LICENSE("GPL");

====================================================================

Makefile文件:


KERN_DIR = /home/linux/linux-3.0.1

all:

  make -C $(KERN_DIR) M=`pwd` modules 

clean:

  make -C $(KERN_DIR) M=`pwd` modules clean

  rm -rf modules.order

obj-m += lcd.o

==================================================================

LCD实验:

想在6410的驱动上面的测试自己的驱动首先要卸载开发板的官方驱动:

1、make menuconfig去掉内核自带的LCD驱动

在Device Drivers=>Graphics support=>S3C Framebuffer Support 

和 

   Device Drivers=>Multimedia support=>Video For Linux

这两项要去掉!

默认:

->Device Drivers

    [*] Multimedia support  ---> 

         [*]   Video For Linux

    ->Graphics support

         [*] S3C Framebuffer Support (eXtended)

               Select LCD Type (4.3 inch 480x272 TFT LCD)  --->

                   (X) 4.3 inch 480x272 TFT LCD

         [*]   Advanced options for S3C Framebuffer

                 Select BPP(Bits Per Pixel) (16 BPP)  --->

                   (X) 16 BPP

         (4)     Number of Framebuffers 

         [*]     Enable Virtual Screen

         [*]     Enable Double Buffering 

改为:

->Device Drivers

    [*] Multimedia support  ---> 

         [ ]   Video For Linux

    ->Graphics support

         [ ] S3C Framebuffer Support (eXtended)

    [*] Support for frame buffer devices  --->   //为了编译出要用的模块

         [M]  Samsung S3C Framebuffer Support

2、上面是去除自带的驱动支持,还要在arch\arm\mach-s3c64xx\mach-smdk6410.c和

change\mach-smdk6410.c这两个文件中相应的结构体注释掉:

s3c_device_vpp

s3c_device_mfc

s3c_device_tvenc

s3c_device_tvscaler

s3c_device_rotator

s3c_device_jpeg

s3c_device_g2d

s3c_device_g3d

这样子 就可以通过编译了:

make zImage                 //生成内核镜像文件

make modules

cp arch/arm/boot/zImage ../../zImage_no_lcd

然后把/drivers/video中的cfbcopyarea.ko 、cfbfillrect.ko 、cfbimgblt.ko 加载到开发板:

cp drivers/video/cfbcopyarea.ko drivers/video/cfbfillrect.ko drivers/video/cfbimgblt.ko ../../../fs_ok6410_yaffs2/driver/

3、把开发板设置为SD卡启动,使用SD卡启动后按空格进入SD卡的u-boot;

4、用SD卡里面的u-boot烧写内核到0x000000200000-0x000000700000 : "Kernel"分区:

tftp 50008000 zImage_no_lcd

nand erase 200000 500000

nand write 50008000 200000 500000

5、烧写完成后设置开发版为nand flash启动,使用新内核启动。

6、测试1:

重启开发板,然后执行以下命令

    insmod cfbcopyarea.ko 

    insmod cfbfillrect.ko 

    insmod cfbimgblt.ko 

    insmod lcd.ko

    echo hello > /dev/tty1

    可以看到屏幕打印了文字hello

    cat lcd.ko > /dev/fb0 

    可以看到花屏了

测试2:

    在开发板的文件系统的/etc/inittab文件中添加一行tty1::askfirst:-/bin/sh

    重启开发板,然后执行以下命令

        insmod cfbcopyarea.ko 

        insmod cfbfillrect.ko 

        insmod cfbimgblt.ko 

        insmod lcd.ko

    可以看到有文字在屏幕上显示,再装载我们之前做的输入子系统的按键驱动

        insmod button_input.ko

    就可以在开发板屏幕上看到shell命令行了


推荐阅读

史海拾趣

Allegro公司的发展小趣事

在公司的快速发展中,BERNSTEIN公司逐渐将目光投向了国际市场。通过与国际知名企业的合作与交流,公司不断引进先进的技术和管理经验,提升了自身的竞争力。同时,BERNSTEIN公司的产品也逐渐在国际市场上赢得了广泛的认可和好评,为公司的发展注入了新的动力。

Cableform Inc公司的发展小趣事

随着技术的不断进步和市场的扩大,Cableform Inc公司意识到必须走出国门,开拓更广阔的市场。1974年,公司在弗吉尼亚州特洛伊成立了北美业务分部,这是公司国际化战略的重要一步。在北美市场,公司面临着激烈的竞争和不同的文化背景,但凭借着优质的产品和服务,Cableform Inc逐渐赢得了客户的信任,市场份额稳步上升。

聚洵(Gainsil)公司的发展小趣事

Cableform Inc公司起源于一位名叫约翰·卡贝尔的电气工程师的创意。在20世纪中期,约翰看到了电子工业的巨大潜力,特别是在电磁控制领域。于是,在1945年,他创立了Cableform Inc,专注于研发和生产电磁控制设备。起初,公司只有几名员工,面临着资金短缺和技术挑战。然而,约翰凭借着对技术的执着和对市场的敏锐洞察,成功设计出了一款具有竞争力的磁铁控制器,为公司的发展奠定了基石。

FILTRAN公司的发展小趣事

进入21世纪,电子行业迎来了快速发展的黄金时期。为了适应市场需求的变化,Cableform Inc不断加大研发投入,致力于技术创新。公司成功开发出了一系列具有自主知识产权的电磁控制产品,涵盖了从直流电机控制到高精度磁铁控制等多个领域。这些技术创新不仅提升了公司的核心竞争力,也为客户提供了更加高效、可靠的解决方案。

西安航天民芯公司的发展小趣事

西安航天民芯科技有限公司成立于XXXX年,创立初期,公司便明确了自己的发展方向——专注于集成电路设计与开发。在创始团队的带领下,公司逐步积累起深厚的技术底蕴,为后续的快速发展奠定了坚实的基础。通过不断地技术研究和创新,西安航天民芯逐渐在行业内崭露头角。

南京绿芯(Grenergy)公司的发展小趣事

随着新能源汽车市场的蓬勃发展,西安航天民芯敏锐地捕捉到了这一机遇。公司投入大量资源进行新能源汽车BMS管理芯片的研发,并成功推出了国内首款新能源汽车专用BMS管理芯片。这一创新产品填补了国内空白,为公司在新能源汽车领域赢得了先机。

问答坊 | AI 解惑

很想知道学会了单片机研发,工资一般能拿多少啊?能达到6000吗?

很想知道学会了单片机研发,工资一般能拿多少啊?能达到6000吗?…

查看全部问答>

中移动Ophone手机主界面曝光 5月底正式发布

本帖最后由 jameswangsynnex 于 2015-3-3 19:57 编辑 5月11日消息,据中国移动相关人士透露,5月中下旬中移动将正式公开发布采用OMS手机操作系统(Open mobile system)的Ophone手机。这将意味着中国自主研发的OMS手机操作系统将正式走上前台,向 ...…

查看全部问答>

【FPGA 代码】

持续赋值方式定义的2 选1 多路选择器module MUX21_1(out,a,b,sel);input a,b,sel;output out;assign out=(sel==0)?a:b;//持续赋值,如果sel 为0,则out=a ;否则out=bendmodule阻塞赋值方式定义的2 选1 多路选择器module MUX21_2(out,a,b,sel);inpu ...…

查看全部问答>

问一个笨笨的问题

请问如何在EVC build后执行某个PC上的EXE文件. 比如,我要在build aa.exe后自动调用bb.exe. 我在post-build里设置,总是不成功.…

查看全部问答>

硬件仿真

想问一下支持硬件仿真的单片机芯片都有哪些  谢谢…

查看全部问答>

WINCE6.0操作系统在三星6410开发板上完美展现!--基于立宇泰ARMSYS6410开发板

精彩测评实例图片说明:1,WINCE6.0系统启动画面(进度条动态显示内核加载进程,LOGO图片可以根据客户需要免费更换);2,WINCE6.0桌面效果;3,800x480液晶屏全屏播放H.264视频流文件(采用硬件解码)4,800x480液晶屏全屏播放MPEG4(avi后缀)音视 ...…

查看全部问答>

我UCOS项目任务优先级划分问题

我在做同步相量测量(PMU) 就是把AD采集的三项交流电压和电流值打上时标然后上传,在接收PC发送的控制命令,如控制继电器开关的命令。由于要对数据打时标(时间戳),底层的PMU采集装置散布在不同的点,每一个点(PMU)安装一个GPS 不现实 ...…

查看全部问答>

Ecan通信的中断问题

       本人在一个项目中运用Ecan进行通信,在通信过程中会碰到中断故障(具体原因说不上来)。我是将Ecan设置成中断接收的(邮箱0-15设置成接收邮箱,16邮箱设置成发送邮箱),若接收到一个合理的读写命令,则返回 ...…

查看全部问答>

g2553定时器的使用问题

#include \"msp430g2553.h\" int main( void ) {   // Stop watchdog timer to prevent time out reset     WDTCTL = WDTPW + WDTHOLD;         P1DIR |= BIT0;     P1OUT &= ~BIT0; & ...…

查看全部问答>

AVR编程软件

我的电脑是64位机,系统是win7的家庭普通版,买电脑觉得送了个win7的正版系统,就没在升旗舰了。 现在在学AVR单片机,老师需要我给编一些程序,但是下了很多相关编程软件,就是用不了(比如CVAVR,ICCAVR). 很困惑,求大神指点!!! 谢谢…

查看全部问答>