Arm9+linux fl2440 dm9000網卡 驅動移植和分析

一、修改內核配置

[shaocongshuai@localhost linux-3.0.2]$ make menuconfig    

         Device Drivers  ---> [*] Network device support  --->[*]   Ethernet (10 or 100Mbit)  ---> <*>   DM9000 support

二、修改 drivers/net/dm9000.c 文件:
頭文件增加:

#include <mach/regs-gpio.h> 

#include <mach/irqs.h>

#include <mach/hardware.h>

dm9000_probe 函數 開始處增加:


unsigned char ne_def_eth_mac_addr[]={0x00,0x12,0x34,0x56,0x80,0x49}; 

 /* 設定默認的mac地址,這個是隨便設(測試用)uboot階段跟Linux階段是兩個階段,uboot階段是一個程序,他有自己的IP、mac。一旦啓動Linux時,uboot不再運行,加載Linux配置自己的IP和mac */
     static void *bwscon;  /* 保存ioremap返回的寄存器的虛擬地址,下同 */
    static void *gpfcon;  
    static void *extint0;  
    static void *intmsk;  


    #define BWSCON           (0x48000000) // Bus Width & Wait Status Control
    #define GPFCON           (0x56000050)  //Port F Control
    #define EXTINT0           (0x56000088)  //External Interrupt Control Register 0
    #define INTMSK           (0x4A000008)  
 /* Determine which interrupt source is masked. The masked
interrupt source will not be serviced.
0 = Interrupt service is available.
1 = Interrupt service is masked.*/
        
       bwscon=ioremap_nocache(BWSCON,0x0000004);  
/*ioremap_nocache 把內存映射到CPU空間  void __iomem * ioremap_nocache (unsigned long phys_addr, unsigned long size); phys_addr  要映射的物理地址   size  要映射資源的大小調用ioremap_nocache()函數之後,返回一個線性地址,此時CPU 可以訪問設備的內存(已經將其映射到了線性地址空間中了),此時CPU可以使用訪問內存的指令訪問設備的內存空間(host bridge 判斷訪問物理內存還是設備中的內存),此時我們就可以像訪問內存一樣來訪問設備的內存(寄存器)。*/
        gpfcon=ioremap_nocache(GPFCON,0x0000004);  
        extint0=ioremap_nocache(EXTINT0,0x0000004);  //32位地址線,每次地址以4個字節爲單位增加
        intmsk=ioremap_nocache(INTMSK,0x0000004);  
 其中BWSCON爲總線寬度 等待控制寄存器

其中第[19:18]位的作用如下


下面函數中將兩位設置爲11,也就是WAIT使能,bank4使用UB/LB。UB/LB是高/低字節選通線,在16位寬的數據線上分開訪問高/低字節時要用到。
      (1)nwe位寫使能信號;(2)nwbe 寫字節使能信號  ,而nBE 爲高/低字節選擇信號。nWBE與nBE共用引腳,可以通過對相關寄存器設置來進行功能選擇            

      nWE和nWBE都帶有寫使能的功能。但既然有nWE,爲什麼還需要nWBE?這是因爲,當使用幾片儲存芯片進行數據位擴展時,有時需要對芯片分開寫數據,此時可使用nWBE。

      僅有一片8bit的ROM,因此僅需要nWE,而不需要nWBE。用了2片8bit的ROM,如果不使用nWBE,則寫操作是對2片ROM同時進行的,這樣當執行寫字節指令時可能會       破壞另一芯片中的數據。(注意nWBE的信號是自動產生的。)從這個角度來說,nWBE有字節數據屏蔽的功能(這裏nGCSn必須是相同的,區別高低位由nWBEx來決定)。
        writel(readl(bwscon)|0xc0000,bwscon);  /* 將BWSCON寄存器[19:18]設置爲11 */
        writel( (readl(gpfcon) & ~(0x3 << 14)) | (0x2 << 14), gpfcon);   /* 設置GPF寄存器 */
       /*GPF7 [15:14] 00 = Input 01 = Output   10 = EINT[7] 11 = Reserved*/
        writel( readl(gpfcon) | (0x1 << 7), gpfcon);  // Disable pull-up,不使能上拉  
        writel( (readl(extint0) & ~(0xf << 28)) | (0x4 << 28), extint0);   //rising edge,設置上升沿觸發中斷  
        writel( (readl(intmsk))  & ~0x80, intmsk);   /* 設置中斷屏蔽寄存器 */  

 

在這個函數的最後有個位置需要修改:

  1. if (!is_valid_ether_addr(ndev->dev_addr)) {  
  2.        /* try reading from mac */  
  3.                   
  4.        mac_src = "chip";  
  5.        for (i = 0; i < 6; i++)  
  6.         //ndev->dev_addr[i] = ior(db, i+DM9000_PAR);   
  7.          ndev->dev_addr[i] = ne_def_eth_mac_addr[i];  
  8. }
三、修改arch/arm/mach-s3c2440/mach-smdk2440.c ,添加設備

  1. static struct platform_device *smdk2440_devices[] __initdata = {  
  2.         &s3c_device_ohci,  
  3.         &s3c_device_lcd,  
  4.         &s3c_device_wdt,  
  5.         &s3c_device_i2c0,  
  6.         &s3c_device_iis,  
  7.         &s3c_device_rtc,  
  8.         &s3c24xx_uda134x,  
  9.         &s3c_device_dm9000,  
  10. };


四、修改 arch/arm/plat-s3c24xx/devs.c  
添加頭文件

#include <linux/dm9000.h>

添加以下代碼

  1. static struct resource s3c_dm9000_resource[] = {   
  2.         [0] = {   //此空間存放的是要發送的地址
  3.         .start = S3C24XX_PA_DM9000,   //實際地址 0x20000300   
  4.         .end   = S3C24XX_PA_DM9000+ 0x3, // 0x20000303
  5.         .flags = IORESOURCE_MEM   //資源標誌位地址資源
  6.         },   
  7.         [1]={   //此空間存放的是要發送的數據
  8.         .start = S3C24XX_PA_DM9000 + 0x4, //CMD pin is A2   
  9.         .end = S3C24XX_PA_DM9000 + 0x4 + 0x7c,   //0x20000380
  10.         .flags = IORESOURCE_MEM   //資源標誌位地址資源
  11.         },   
  12.         [2] = {   
  13.         .start = IRQ_EINT7, // 中斷爲外部7號中斷 
  14.         .end   = IRQ_EINT7,   // 中斷爲外部7號中斷  
  15.         .flags = IORESOURCE_IRQ   //標誌爲中斷資源
  16.         },   
  17.         };   
  18.    
  19.         static struct dm9000_plat_data s3c_device_dm9000_platdata = {   
  20.         .flags= DM9000_PLATF_16BITONLY,   //傳送數據總線爲16位寬度
  21.         };   
  22.    
  23.         struct platform_device s3c_device_dm9000 = {   
  24.         .name= "dm9000",   
  25.         .id= 0,   
  26.         .num_resources= ARRAY_SIZE(s3c_dm9000_resource),   
  27.         .resource= s3c_dm9000_resource,   
  28.           .dev= {   
  29.         .platform_data = &s3c_device_dm9000_platdata,   
  30.           }   
  31. };   
  32. EXPORT_SYMBOL(s3c_device_dm9000);
      網絡對於嵌入式系統來說必不可少。可是s3c2440沒有集成以太網接口,所以要想使s3c2440具備以太網的功能,就必須擴展網卡接口。在這裏,我們外接DM9000,使其可以與以太網相連接。
       DM9000可以直接與ISA總線相連,也可以與大多數CPU相連。在這裏,我們當然是要讓DM9000與s3c2440相連接了。

      其實DM9000只有2個口,命令口和數據口,由CMD決定,至於你說的300基地址,是當有多個DM9000掛在同一總線上時用來區分它們的,如果你只掛了一個DM9000,就可以直接把DM9000的高地址相應位接地或VCC,低地址位用來區分寄存器地址
     “DM9000對外來說只有兩個端口——地址口和數據口,地址口用於輸入內部寄存器的地址,而數據口則完成對某一寄存器的讀寫。DM9000的CMD引腳用來區分這兩個端口,當CMD引腳爲0時,DM9000的數據線上傳輸的是寄存器地址,當CMD引腳爲1時,傳輸的是讀寫數據。我們把DM9000的AEN接到s3c2440的nGCS4引腳上,則DM9000的端口基址爲0x20000300,如果再把DM9000的CMD引腳接到s3c2440的ADDR2引腳上”
 
     我們所說的地址:0x20000000 和 0x20000004 是由ARM芯片的地址引腳決定的,注意,這個地址表示是用的16進制,那麼,0x20000004的每一位的值都可以是0~f,它由ARM的4根地址線的電平高,比如最低的一     位,就是由 ADDR3~ADDR0 這4個引腳的電平決定,如果 ADDR3~ADDR0 = 1111,則該位爲f ,如果 LADDR3~LADDR0 = 0100,則該位爲 4
     因此,如果將 DM9000的CMD引腳接到s3c2440的ADDR2,由於CMD引腳的高低電平決定地址口和數據口,那麼,ADDR2爲0時,訪問的就是地址口,所以地址口的起始地址爲 ARRD2爲0的情況,即0x20000000 ;ADDR2爲1   時,(LADDR3~LADDR0 = 0100)訪問的就是數據口,所以數據口的地址即 0x20000004。

      看到沒?就是CMD這個引腳,dm9000數據手冊上有這樣一句:

      Command Type

     When high, the access of this command cycle is DATA port

      When low, tha access of this command cycle is ADDRESS port

      這個CMD引腳爲高電平時,是數據端口,CMD爲低電平時,位地址端口。而我的開發板上CMD口接的是LADDR2,也就是第三根地址線,在bank4中,當地址小於四個字節時,該引腳爲低電平,使用地址端口,而在大於四個字節而小於八個字節時是高電平,使用數據端口,這樣,我們就可以很清楚的知道了,resource[0]就是定義了地址端口,而resource[0]則定義了數據端口,更進一步,只要以8爲倍數的bank4的地址爲一組,都可以用來使用,只要保證期間LADDR2只變化一次。看後面的例子時,這點將予以體現。

        所以地址寫成0x20000000-------0x20000000+128M之間都是可以的,但是注意:addr2必須爲0,因爲dm9000是地址線和數據線複用的, 它根本沒有用到cup的地址線,他的地址只根驅動寫地址命令裏面的數據有關。


        這樣我們把要發送的dm9000的地址信息固定放在了0x20000300,把要存放在該地址的數據存放在0x2000 0304。(因爲地址和數據線複用,所以地址和數據需要分兩次傳送),即:數組【0】是dm9000要取的地址,數組【1】存放dm9000地址對應要存放的數據。數組[2]外部中斷號 
      .end= MACH_MINI2440_DM9K_BASE + 3,爲什麼尾地址是+3? 
      因爲一個地址需要四個字節。   
      數組【1】.start= MACH_MINI2440_DM9K_BASE + 4,爲什麼? 
      注意這個地址是不能隨便選的,必須根據數組【0】.start地址和硬件連接情況進行對應的。
      爲什麼MACH_MINI2440_DM9K_BASE定義的時候addr2爲能爲0.? 
       Addr2即是Cup的地址線addr0-----addr26中的一員: 1、它的任何一位變化都會使得當前CPU訪問的地址發生變化。 2、他連接着dm9000的數據/地址選通引腳,即:addr2=0則寫的是地址,addr2=1則寫的是數據。 因爲當我們的基址是:0x2000 0300的時候,我們現在要寫數據了,這時候把addr2置高電平也就是1就開始寫數據了,同時cup的訪問地址發生改變,變成0x20000304了。(這樣做有一個好處,就是我們要寫地址了就寫到0x2000 0300,要寫數據了就寫到0x20000300+4,而不需要特意的去改變選通腳狀態。不需要寫地址的時候特意置0,在寫數據的時候特意置1,因爲我們訪問方式改變的時候選通也會隨着改變。) 反過來,我們要設這個地址存放是dm9000的地址還是數據時要考慮addr2的情況。也就MACH_MINI2440_DM9K_BASE這個地址可以設addr2=0的,0x20000000-------0x20000000+128M的任何一個地址。當然不同的開發板可能會不一樣,我們硬件可以換成addr2----addr26中的任何一位。 (addr0,addr1,因爲一個數據需要四個字節存放,所以這兩位不能做爲選通引腳,不然兩個存放地址就有重疊的地方了,如果一個數據是一個字節大小則可以) 
       比如說:我們硬件設定addr3爲dm9000讀寫選通引腳,MACH_MINI2440_DM9K_BASE就設成0x20000000,那麼可以這樣寫: [0] = { 
       .start = MACH_MINI2440_DM9K_BASE,                //addr3=0,此空間存放的是要發送的地址 
       .end = MACH_MINI2440_DM9K_BASE + 3, .flags = IORESOURCE_MEM }, 
        [1] = { 
        .start = MACH_MINI2440_DM9K_BASE + 8,        //addr3=1,此空間存放的是要發送的數據 .end = MACH_MINI2440_DM9K_BASE + 11, .flags = IORESOURCE_MEM },

五、修改 arch/arm/plat-samsung/include/plat/devs.h    45行附近,添加
extern struct platform_device s3c_device_dm9000; 

六、修改arch/arm/mach-s3c2410/include/mach/map.h 文件

/* DM9000 */ 

#define   S3C24XX_PA_DM9000 0x20000300 

#define   S3C24XX_VA_DM9000 0xE0000000

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