嵌入式2D加速顯卡SM501驅動的移植[linux.2.6.18]

本文從三個方面說明一下SM501顯卡驅動在2440+2.6.18環境下的移植:
1 硬件情況。
2 移植過程
3 驅動測試

一、硬件情況:
第一次接觸到顯卡編程,有點不太適應。SM501的Datasheet寫的太簡略,個人覺得有用的基本上就是兩個方面:

內存映射模式。
2440與 SM501連接模式爲2440作爲HOST有獨立的SDRAM,SM501除了可以訪問HOSTSDRAM外,還擁有8MB的本地內存作爲 FrameBuffer。SM501的幀緩存與IO寄存器佔有64M地址空間。其中0~62M屬於Framebuffer,高2M地址空間屬於SM501 的IO寄存器端口地址MMIO_BASE。這2M IO端口空間中每64KB屬於一組接口寄存器。 在我的板子上,SM501的64M地址空間映射在2440的 0x800_0000~0x1000_1000範圍內。即FrameBuffer的起始物理地址爲0x800_0000,SM501 MMIO_BASE 地址0xBE0_0000。 這些對於移植驅動來說應該已經足夠。
基本配置。由於兩個原因:1是對於圖形顯示芯片的基本知識欠缺,2是SM501的Datasheet實在不怎麼樣,太簡略。應該是具體的配置還不太清晰。 主要方面如下:
1)系統設置  :系統配置,DRAM配置時序等,GPIO功能配置。
2)2D加速操作。設置寄存器的值和命令,啓動圖形加速操作。
3)LCD接口設置 
4)CRT 接口設置

二、SM501驅動在2.6.18內核下的移植過程:
下載SM501驅動,版本0.05,按照其readme.txt的說法,支持2.6.4內核和2.4.20。
開發板環境s3c2440 + linux2.6.18。

 


1)按照驅動目錄下的readme.txt,先將4個驅動源文件voyage.c(.h),smi2d.c(.h)拷貝到driver/vedio/下面。
2)在該目錄下修改與編譯相關的Kconfig和Makefile:
首先修改Kconfig文件,在menu "Graphics support" 菜單,config FB選項下邊 添加選項
# added by beelike ,for sm501 support !!
config FB_SM501_KERNEL_2_6_X
bool "Silicon Motion, Inc. SM501 support"
depends on FB
choice
在Makefile中 添加 編譯規則 :
obj-$(CONFIG_FB_SM501_KERNEL_2_6_X)  += voyager.o smi2d.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
3)在make menuconfig 中,選中Frame buffer 支持,LOGO,SM501支持。 
下面是源代碼的修改。
使驅動默認支持支持1024*768*32 CRT顯示。
4)在voyager.h中,相關修改
#define isPC 0      //非PC系統
#define isPCI 0 //非PCI總線
#define SCREEN_X_RES 1024  //水平分辨率
#define SCREEN_Y_RES 768 //480
#define SCREEN_BPP 32 // BPP

#define isACCELENT 0 /* 2440 非 Accelent 平臺*/
#define FB_PHYSICAL_ADDR  0x08000000  //nGCS1 
#define REG_PHYSICAL_ADDR 0x0BE00000  //0x08000000+62M的地址爲MMIO_BASE

voyager.h修改結束。

5)接下來的移植過程與readme.txt中的大不相同。我想是因爲2.6.4與2..6.18版本的不一樣。 Readme.txt中 說到將voyager.c中sm501fb_init函數添加到fbmem.c中的fb_drivers數組中去,然而,2.6.18的內核已經沒有這個 數組了。添加到這個數組中無非就是爲了使得在啓動的時候sm501fb_init得到執行而已。我想到的辦法是使用 module_init(sm501fb_init)。事實證明,這樣做是正確的。

6)在sm501fb_init函數中添加外部晶振頻率設定。驅動源碼中默認使用24M,但是我的板子上使用的是12M。

在sm501fb_init中添加:
    //beelike add , here set extern cystal clock =12M .
crystal=regRead32(MISC_CTRL);
crystal=FIELD_SET(crystal,MISC_CTRL,CRYSTAL,12);
regWrite32(MISC_CTRL, crystal);
//end add 
添加的位置必須在對SM501的64M緩存進行ioremap之後,否則會出現Oops。

如果顯存不爲8M,可以在sm501fb_init函數中設置。驅動默認設置的是8M。
7)設置CRT模式,修改smi_set_timing函數中的panelSetMode爲crtSetMode。
static void smi_set_timing(struct smifb_info *sfb,struct par_info *hw)
{
//panelSetMode(hw->width, hw->height, 0, hw->hz, sfb->fb.var.bits_per_pixel); 
crtSetMode(hw->width, hw->height, 0, hw->hz, sfb->fb.var.bits_per_pixel); 
// Turn on CRT DAC. for simultanous display
regWrite32(MISC_CTRL, FIELD_SET(regRead32(MISC_CTRL),  MISC_CTRL,  DAC_POWER, NABLE));
}


8) 其它改動:主要是添加了module_exit清理函數。
在voyager.c頭文件包含下面定義全局指針:
//added by beelike  
struct smifb_info *gpinfo=NULL;/*驅動數據結構的全局變量,清理函數引用它來註銷和釋放資源。*/

在sm501fb_init()中修改:
gpinfo=sfb = smi_alloc_fb_info(pdev, name);
在voyager.c末尾添加:
/*
*  beelike add 
*/
void sm501fb_exit(void)
{
if(!gpinfo) return;
smi_unmap_smem(gpinfo);
smi_unmap_mmio(gpinfo);
unregister_framebuffer(&(gpinfo->fb));
smi_free_fb_info(gpinfo);
}
module_init(sm501fb_init);
module_exit(sm501fb_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("SM501 Framebuffer driver .");
/**end add **/

 

9)其它被證明爲沒有必要的修改:
添加頭文件:
#include 
/*beelike add  這裏添加對bank1的DRAM控制寄存器設置*/
#define S3C2410_BWSCON_DW1 (3<<4)
void sm501_hwinit(void)
{ volatile unsigned int * p;
p= S3C2410_BWSCON;
*p = (*p & (~(S3C2410_BWSCON_ST1| S3C2410_BWSCON_WS1|S3C2410_BWSCON_DW1)));
  *p = (*p)|(S3C2410_BWSCON_ST1| S3C2410_BWSCON_WS1 |S3C2410_BWSCON_DW1_32);
p=S3C2410_BANKCON1;
*p= S3C2410_BANKCON_Tacs0|S3C2410_BANKCON_Tcos4|S3C2410_BANKCON_Tacc14|S3C2410_BANKCON_Tcoh1 | S3C2410_BANKCON_Tcah4 | S3C2410_BANKCON_Tacp6 | S3C2410_BANKCON_PMCnorm;
}
/* 雖然被證明沒有必要,那因爲內核或者u-boot已經對這兩個寄存器做過正確設置,如果移植失敗,則的確應該考慮內存控制器的設置問題 end add */

整體來說,移植SM501驅動還是比較順利的。系統啓動後在屏幕左上角安靜顯示了小企鵝。

 

三、驅動測試:(Framebuffer 編程)

所有的fb驅動擁有同一個FB_MAJOR(29)。SM501顯卡驅動在我的板上佔用的minor=0。先生成節點:

mknod /dev/fb0 c 29 0

然後使用程序fbtest.c測試,源碼如下:(此源碼來自網絡,略加修改)
#include
#include
#include
#include
#include

int main()
{
        int fbfd = 0;
        struct fb_var_screeninfo vinfo;
        struct fb_fix_screeninfo finfo;
        long int screensize = 0;
        int * fbp = 0;
        int i;
       
        fbfd = open("/dev/fb0", O_RDWR);
        if (!fbfd) {
                printf("Error: cannot open framebuffer device./n");
                exit(1);
        }

        if (ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo)) {
                printf("Error reading fixed information./n");
                exit(2);
        }
        if (ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo)) {
                printf("Error reading variable information./n");
                exit(3);
        }
        screensize = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8;
        fbp = (int *)mmap(0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED,fbfd, 0);
        if ((int)fbp == -1) {
                printf("Error: failed to map framebuffer device to memory./n");
                exit(4);
        }
        printf("/dev/fb0:/n xres=%d,yres=%d,bpp=%d/n",vinfo.xres,vinfo.yres,vinfo.bits_per_pixel);
        for(i=0;i
         *(fbp+i) = 255<<8 ;
        munmap(fbp, screensize);
        close(fbfd);
        return 0;
}

交叉編譯,下載執行,CRT屏幕顯示整屏綠色。測試成功。




在移植過程中主要參考readme.txt和網絡上兩篇好文章:
http://www.eetop.cn/blog/html/38/12938-11581.html
http://blog.csdn.net/listream1/archive/2006/11/06/1369361.aspx
這兩篇文章是基於2.4版內核的。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章