一、修改內核配置
[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); /* 設置中斷屏蔽寄存器 */
在這個函數的最後有個位置需要修改:
- if (!is_valid_ether_addr(ndev->dev_addr)) {
- /* try reading from mac */
- mac_src = "chip";
- for (i = 0; i < 6; i++)
- //ndev->dev_addr[i] = ior(db, i+DM9000_PAR);
- ndev->dev_addr[i] = ne_def_eth_mac_addr[i];
- }
- static struct platform_device *smdk2440_devices[] __initdata = {
- &s3c_device_ohci,
- &s3c_device_lcd,
- &s3c_device_wdt,
- &s3c_device_i2c0,
- &s3c_device_iis,
- &s3c_device_rtc,
- &s3c24xx_uda134x,
- &s3c_device_dm9000,
- };
四、修改 arch/arm/plat-s3c24xx/devs.c
添加頭文件
#include <linux/dm9000.h>
添加以下代碼
- static struct resource s3c_dm9000_resource[] = {
- [0] = { //此空間存放的是要發送的地址
- .start = S3C24XX_PA_DM9000, //實際地址 0x20000300
- .end = S3C24XX_PA_DM9000+ 0x3, // 0x20000303
- .flags = IORESOURCE_MEM //資源標誌位地址資源
- },
- [1]={ //此空間存放的是要發送的數據
- .start = S3C24XX_PA_DM9000 + 0x4, //CMD pin is A2
- .end = S3C24XX_PA_DM9000 + 0x4 + 0x7c, //0x20000380
- .flags = IORESOURCE_MEM //資源標誌位地址資源
- },
- [2] = {
- .start = IRQ_EINT7, // 中斷爲外部7號中斷
- .end = IRQ_EINT7, // 中斷爲外部7號中斷
- .flags = IORESOURCE_IRQ //標誌爲中斷資源
- },
- };
- static struct dm9000_plat_data s3c_device_dm9000_platdata = {
- .flags= DM9000_PLATF_16BITONLY, //傳送數據總線爲16位寬度
- };
- struct platform_device s3c_device_dm9000 = {
- .name= "dm9000",
- .id= 0,
- .num_resources= ARRAY_SIZE(s3c_dm9000_resource),
- .resource= s3c_dm9000_resource,
- .dev= {
- .platform_data = &s3c_device_dm9000_platdata,
- }
- };
- EXPORT_SYMBOL(s3c_device_dm9000);
DM9000可以直接與ISA總線相連,也可以與大多數CPU相連。在這裏,我們當然是要讓DM9000與s3c2440相連接了。
我們所說的地址: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的地址線,他的地址只根驅動寫地址命令裏面的數據有關。
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,此空間存放的是要發送的地址
[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行附近,添加
六、修改arch/arm/mach-s3c2410/include/mach/map.h 文件
/* DM9000 */
#define S3C24XX_PA_DM9000 0x20000300
#define S3C24XX_VA_DM9000 0xE0000000