Fedora-ARM
全部博文(241)
分类: LINUX
2007-09-27 11:58:38
......
DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_STOP);
DP_OUT(base, DP_TCR, DP_TCR_NORMAL); /* Normal transmit operations */
DP_OUT(base, DP_RCR, DP_RCR_AB); /* Accept broadcast, no errors, no multicast */
DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_START);
dp->running = true;
}
......
static void
dp83902a_send(unsigned short *data, int total_len, unsigned long key)
{
......
DP_OUT(base, DP_ISR, DP_ISR_RDC); /* Clear end of DMA */
{
/* Dummy read. The manual sez something slightly different, */
/* but the code is extended a bit to do what Hitachi's monitor */
/* does (i.e., also read data). */
/* //屏蔽无用的语句
cyg_uint16 tmp;
int len = 1;
DP_OUT(base, DP_RSAL, 0x100-len);
DP_OUT(base, DP_RSAH, (start_page-1) & 0xff);
DP_OUT(base, DP_RBCL, len);
DP_OUT(base, DP_RBCH, 0);
DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_RDMA | DP_CR_START);
DP_IN_DATA(dp->data, tmp);
*/ }
......
#if DEBUG & 4
printf(" sg buf %08lx len %08x\n ", (unsigned long) data, len);
dx = 0;
#endif
while (len > 1) {
#if DEBUG & 4
printf(" %04x", *data);
if (0 == (++dx % 16)) printf("\n ");
#endif
DP_OUT_DATA(dp->data, *data++);
len-=2;
}
#if DEBUG & 4
if (len==1) printf(" %04x", (*data)&0xff);
printf("\n");
#endif
if (len==1) {DP_OUT_DATA(dp->data, (*data++)&0xff); total_len++; }
if (total_len < pkt_len) {
#if DEBUG & 4
printf(" + %d bytes of padding\n", pkt_len - total_len);
#endif
/* Padding to 802.3 length was required */
for (i = total_len; i < pkt_len;) {
i+=2;
DP_OUT_DATA(dp->data, 0);
}
}
......
}
/*
This function is called when a packet has been received. It's job is
to prepare to unload the packet from the hardware. Once the length of
the packet is known, the upper layer of the driver can be told. When
the upper layer is ready to unload the packet, the internal function
'dp83902a_recv' will be called to actually fetch it from the hardware.
*/
static void
dp83902a_RxEvent(void)
{
struct dp83902a_priv_data *dp = (struct dp83902a_priv_data *) &nic;
cyg_uint8 *base = dp->base;
unsigned char rsr;
unsigned short rcv_hdr[2];
int i, len, pkt, cur;
......
DP_OUT(base, DP_RBCL, 4);
DP_OUT(base, DP_RBCH, 0);
DP_OUT(base, DP_RSAL, 0);
DP_OUT(base, DP_RSAH, pkt);
if (dp->rx_next == pkt) {
if (cur == dp->rx_buf_start)
DP_OUT(base, DP_BNDRY, dp->rx_buf_end-1);
else
DP_OUT(base, DP_BNDRY, cur-1); /* Update pointer */
return;
}
dp->rx_next = pkt;
DP_OUT(base, DP_ISR, DP_ISR_RDC); /* Clear end of DMA */
DP_OUT(base, DP_CR, DP_CR_RDMA | DP_CR_START);
#ifdef CYGHWR_NS_DP83902A_PLF_BROKEN_RX_DMA
CYGACC_CALL_IF_DELAY_US(10);
#endif
for (i = 0; i < sizeof(rcv_hdr);) {
DP_IN_DATA(dp->data, rcv_hdr[i++]);
}
#if DEBUG & 5
printf("rx hdr %04x %04x \n",
rcv_hdr[0], rcv_hdr[1]);
#endif
len = rcv_hdr[1] - 4;
uboot_push_packet_len(len);
if (((rcv_hdr[0] >>8)&0xff) == dp->rx_buf_start)
DP_OUT(base, DP_BNDRY, dp->rx_buf_end-1);
else
DP_OUT(base, DP_BNDRY, ((rcv_hdr[0] >>8)&0xff)-1); /* Update pointer */
}
}
/*
This function is called as a result of the "eth_drv_recv()" call above.
It's job is to actually fetch data for a packet from the hardware once
memory buffers have been allocated for the packet. Note that the buffers
may come in pieces, using a scatter-gather list. This allows for more
efficient processing in the upper layers of the stack.
*/
static void
dp83902a_recv(unsigned short *data, int len)
{
......
/* Read incoming packet data */
DP_OUT(base, DP_CR, DP_CR_PAGE0 | DP_CR_NODMA | DP_CR_START);
DP_OUT(base, DP_RBCL, len & 0xFF);
DP_OUT(base, DP_RBCH, (len >> 8)& 0xFF);
DP_OUT(base, DP_RSAL, 4); /* Past header */
DP_OUT(base, DP_RSAH, dp->rx_next);
DP_OUT(base, DP_ISR, DP_ISR_RDC); /* Clear end of DMA */
DP_OUT(base, DP_CR, DP_CR_RDMA | DP_CR_START);
#ifdef CYGHWR_NS_DP83902A_PLF_BROKEN_RX_DMA
CYGACC_CALL_IF_DELAY_US(10);
#endif
saved = false;
for (i = 0; i < 1; i++) {
if (data) {
mlen = len;
#if DEBUG & 4
printf(" sg buf %08lx len %08x \n", (unsigned long) data, mlen);
dx = 0;
#endif
while (0 < mlen) {
/* Saved byte from previous loop? */
if (saved) {
*data++ = saved_char;
mlen--;
saved = false;
continue;
}
{
cyg_uint16 tmp;
DP_IN_DATA(dp->data, tmp);
#if DEBUG & 4
printf(" %04x", tmp);
if (0 == (++dx % 16)) printf("\n ");
#endif
*data++ = tmp;
mlen-=2;
if (mlen==1) {
DP_IN_DATA(dp->data, tmp);
tmp = tmp & 0xff;
#if DEBUG & 4
printf(" %04x", tmp);
#endif
*data++ = tmp;
mlen--;
}
}
}
#if DEBUG & 4
printf("\n");
#endif
}
}
}
......
//添加自定义的AX88796硬件信息,在这里定义了如果网卡的MAC地址的前三个为
//0x08, 0x08, 0x08,那就是AX88796。如果你要修改MAC地址 ,
//最好前三个要和这三个一样,不然驱动会认不到网卡。
static hw_info_t hw_info[] = {
......
{ /* NE2000 Compatible */ 0x0ff0, 0x00, 0xa0, 0x0c, 0 },
{ /* AX88796 */ 0x0ff0, 0x08, 0x08, 0x08, 0 },
{ /* Network General Sniffer */ 0x0ff0, 0x00, 0x00, 0x65,
......
};
......
static void pcnet_reset_8390(void)
{
int i, r;
PRINTK("nic base is %lx\n", nic_base);
#if 1
n2k_outb(E8390_NODMA+E8390_PAGE0+E8390_STOP, E8390_CMD);
PRINTK("cmd (at %lx) is %x\n", nic_base+ E8390_CMD, n2k_inb(E8390_CMD));
n2k_outb(E8390_NODMA+E8390_PAGE1+E8390_STOP, E8390_CMD);
PRINTK("cmd (at %lx) is %x\n", nic_base+ E8390_CMD, n2k_inb(E8390_CMD));
n2k_outb(E8390_NODMA+E8390_PAGE0+E8390_STOP, E8390_CMD);
PRINTK("cmd (at %lx) is %x\n", nic_base+ E8390_CMD, n2k_inb(E8390_CMD));
#endif
n2k_outb(E8390_NODMA+E8390_PAGE0+E8390_STOP, E8390_CMD);
n2k_outb(n2k_inb(PCNET_RESET), PCNET_RESET);
//低级错误,严重的BUG,没有修改无法实现网卡的热复位,晕死。
for (i = 0; i < 100; i++) {
if ((r = (n2k_inb(EN0_ISR) & ENISR_RESET)) != 0)
break;
PRINTK("got %x in reset\n", r);
my_udelay(100);
}
n2k_outb(0xff, EN0_ISR); /* Ack intr. */
if (i == 100)
printf("pcnet_reset_8390() did not complete.\n");
} /* pcnet_reset_8390 */
static hw_info_t * get_prom(void ) {
unsigned char prom[32];
char ethaddr[20]; //tekkaman
int i, j, tekkaman; //tekkaman
unsigned char ne_defethaddr[]={0x08,0x08,0x08,0x08,0x12,0x27,0};//tekkaman
......
pcnet_reset_8390();
mdelay(10);
for (i = 0; i < sizeof(program_seq)/sizeof(program_seq[0]); i++)
n2k_outb(program_seq[i].value, program_seq[i].offset);
tekkaman=ne2000_read_mac_addr(prom);
if (tekkaman) {
printf("ethaddr in nand is not found ,loading ne_defethaddr:");
for (i = 0; i < 12; i++) {
prom[i] = ne_defethaddr[i/2];
printf(" %02x", prom[i]);
}
}
prom[28] = prom[30] = 0x57;
PRINTK("\n");
for (i = 0; i < NR_INFO; i++) {
if ((prom[0] == hw_info[i].a0) &&
(prom[2] == hw_info[i].a1) &&
(prom[4] == hw_info[i].a2)) {
PRINTK("matched board %d\n", i);
break;
}
}
if ((i < NR_INFO) || ((prom[28] == 0x57) && (prom[30] == 0x57))) {
for (j = 0; j < 6; j++)
dev_addr[j] = prom[j<<1];
PRINTK("on exit i is %d/%ld\n", i, NR_INFO);
PRINTK("MAC address is %02x:%02x:%02x:%02x:%02x:%02x\n",
dev_addr[0],dev_addr[1],dev_addr[2],dev_addr[3],dev_addr[4],dev_addr[5]);
return (i < NR_INFO) ? hw_info+i : &default_info;
if (tekkaman) {
sprintf (ethaddr, "%02X:%02X:%02X:%02X:%02X:%02X",
dev_addr[0], dev_addr[1],
dev_addr[2], dev_addr[3],
dev_addr[4], dev_addr[5]) ;
printf("Set environment from HW MAC addr = \"%s\"\n", ethaddr);
setenv ("ethaddr", ethaddr);
}
}
return NULL;
}
/* U-boot specific routines */
#define NB 5
static unsigned short *pbuf = NULL;
static int plen[NB];
static int nrx = 0;
static int pkey = -1;
void uboot_push_packet_len(int len) {
PRINTK("pushed len = %d, nrx = %d\n", len, nrx);
if (len>=2000) {
printf("NE2000: packet too big\n");
return;
}
if (nrx >= NB) {
printf("losing packets in rx\n");
return;
}
plen[nrx] = len;
dp83902a_recv(&pbuf[nrx*1000], len);
nrx++;
}
void uboot_push_tx_done(int key, int val) {
PRINTK("pushed key = %d\n", key);
pkey = key;
}
int eth_init(bd_t *bd) {
static hw_info_t * r;
// char ethaddr[20];
PRINTK("### eth_init\n");
if (!pbuf) {
pbuf = malloc(NB*1000);
if (!pbuf) {
printf("Cannot allocate rx buffers\n");
return -1;
}
}
#ifdef CONFIG_DRIVER_NE2000_CCR
{
volatile unsigned char *p = (volatile unsigned char *) CONFIG_DRIVER_NE2000_CCR;
PRINTK("CCR before is %x\n", *p);
*p = CONFIG_DRIVER_NE2000_VAL;
PRINTK("CCR after is %x\n", *p);
}
#endif
nic_base = CONFIG_DRIVER_NE2000_BASE;
nic.base = (cyg_uint8 *) CONFIG_DRIVER_NE2000_BASE;
r = get_prom();
if (!r)
return -1;
/*//屏蔽无用的语句
sprintf (ethaddr, "%02X:%02X:%02X:%02X:%02X:%02X",
dev_addr[0], dev_addr[1],
dev_addr[2], dev_addr[3],
dev_addr[4], dev_addr[5]) ;
PRINTK("Set environment from HW MAC addr = \"%s\"\n", ethaddr);
setenv ("ethaddr", ethaddr);
*/
#define DP_DATA 0x10
nic.data = (unsigned short *) (nic.base + DP_DATA);
nic.tx_buf1 = 0x40;
nic.tx_buf2 = 0x46;
nic.rx_buf_start = 0x4C;
nic.rx_buf_end = 0x80;
dp83902a_start(dev_addr);
if (dp83902a_init() == false)
return -1;
return 0;
}
void eth_halt() {
PRINTK("### eth_halt\n");
dp83902a_stop();
}
int eth_rx() {
int j, tmo;
volatile uchar * inpkt
PRINTK("### eth_rx\n");
tmo = get_timer (0) + TOUT * CFG_HZ;
while(1) {
dp83902a_poll();
if (nrx > 0) {
for(j=0; j
NetReceive(inpkt, plen[j]);//这句的作用就是将接收到的数据
//送到MAC层以上的协议层
}
nrx = 0;
return 1;
}
if (get_timer (0) >= tmo) {
printf("timeout during rx\n");
return 0;
}
}
return 0;
}
int eth_send(volatile void *packet, int length) {
int tmo;
PRINTK("### eth_send\n");
pkey = -1;
dp83902a_send((unsigned short *) packet, length, 666);
tmo = get_timer (0) + TOUT * CFG_HZ;
while(1) {
dp83902a_poll();
if (pkey != -1) {
PRINTK("Packet sucesfully sent\n");
return 0;
}
if (get_timer (0) >= tmo) {
printf("transmission error (timoeut)\n");
return 0;
}
}
return 0;
}
#endif
ne2000.c修改完毕
(2)修改ne2000.h
NE2000驱动的低级错误
将第45行:
at */
改为:
at
就是去掉“*/” , 真是TNND汗死!!!!
......
#define DP_IN(_b_, _o_, _d_) (_d_) = *( (volatile unsigned char *) ((_b_)+(_o_)))
#define DP_OUT(_b_, _o_, _d_) *( (volatile unsigned char *) ((_b_)+(_o_))) = ((unsigned char) (_d_))
#define DP_IN_DATA(_b_, _d_) (_d_) = *( (volatile unsigned short *) ((_b_)))
#define DP_OUT_DATA(_b_, _d_) *( (volatile unsigned short *) ((_b_))) = ((unsigned short) (_d_))
/* here is all the data */
#define cyg_uint8 unsigned char
#define cyg_uint16 unsigned short
#define bool int
#define false 0
#define true 1
#define CYGHWR_NS_DP83902A_PLF_BROKEN_TX_DMA 1
#define CYGACC_CALL_IF_DELAY_US(X) my_udelay(X)
typedef struct dp83902a_priv_data {
cyg_uint8* base;
cyg_uint16* data;
cyg_uint8* reset;
int tx_next; /* First free Tx page */
int tx_int; /* Expecting interrupt from this buffer */
int rx_next; /* First free Rx page */
int tx1, tx2; /* Page numbers for Tx buffers */
unsigned long tx1_key, tx2_key; /* Used to ack when packet sent */
int tx1_len, tx2_len;
bool tx_started, running, hardwired_esa;
cyg_uint8 esa[6];
void* plf_priv;
/* Buffer allocation */
int tx_buf1, tx_buf2;
int rx_buf_start, rx_buf_end;
} dp83902a_priv_data_t;
......
(3)修改8390.h
......
/*
* Only generate indirect loads given a machine that needs them.
* - removed AMIGA_PCMCIA from this list, handled as ISA io now
*/
#define n2k_inb(port) (*((volatile unsigned char *)(port+CONFIG_DRIVER_NE2000_BASE)))
#define n2k_outb(val,port) (*((volatile unsigned char *)(port+CONFIG_DRIVER_NE2000_BASE)) = ((unsigned char) val))
#define EI_SHIFT(x) (x)
......
网卡驱动程序的修改到此结束,以下是总线参数的修改:
修改/board/tekkaman/tekkaman2410/lowlevel_init.S文件(参数都是参考 刘淼 的书):
#define B1_BWSCON (DW16)
#define B2_BWSCON (DW16 + UBLB)
#define B3_BWSCON (DW16)
......
#define B2_Tacs 0x3 /* 4clk tekkaman*/
#define B2_Tcos 0x3 /* 4clk tekkaman*/
#define B2_Tacc 0x7 /* 14clk */
#define B2_Tcoh 0x3 /* 4clk tekkaman*/
#define B2_Tah 0x3 /* 4clk tekkaman*/
#define B2_Tacp 0x3 /* 6clk tekkaman*/
#define B2_PMC 0x0 /* normal */
......
U-Boot下的AX88796移植结束了,我有复查过,应该在编译网卡驱动的时候连警告都不会有,所以如果您遇到了问题,在检查是否按照上面步骤移植后,还不能解决,可以联系我,QQ:78027228。不过我建议:最好是在看过我介绍的资料后再来移植,出了问题你自己就可以解决了。下一步的目标是U-Boot和Linux下的LCD驱动。以下附上我启动时和运行的输出信息(请注意U-Boot环境变量的设定):
U-Boot 1.2.0 (Sep 25 2007 - 14:59:27)
U-Boot code: 33F80000 -> 33F98BC0 BSS: -> 33F9D3C0
DRAM: 64 MB
NAND: 64 MB
In: serial
Out: serial
Err: serial
Hit any key to stop autoboot: 0
[Tekkaman2410]# printenv
bootdelay=3
baudrate=115200
ethaddr=08:08:08:08:12:27
netmask=255.255.255.0
bootfile=zImage.img
loadaddr=0x30008000
bootargs=root=/dev/nfs rw nfsroot=192.168.1.22:/home/tekkaman/working/rootfs ip=192.168.1.2:192.168.1.22::255.255.255.0 console=ttySAC0,115200 init=/linuxrc mem=64M
bootcmd=tftp;bootm
ipaddr=192.168.1.2
serverip=192.168.1.22
stdin=serial
stdout=serial
stderr=serial
Environment size: 382/65532 bytes
U-Boot 1.2.0 (Sep 25 2007 - 14:59:27)
U-Boot code: 33F80000 -> 33F98BC0 BSS: -> 33F9D3C0
DRAM: 64 MB
NAND: 64 MB
In: serial
Out: serial
Err: serial
Hit any key to stop autoboot: 0
### eth_init
matched board 31
AX88796 - tekkmana ESA: 08:08:08:08:12:27
TFTP from server 192.168.1.22; our IP address is 192.168.1.2
Filename 'zImage.img'.
Load address: 0x30008000
Loading: #################################################################
#################################################################
#################################################################
#################################################################
#################################################################
#############
done
Bytes transferred = 1727136 (1a5aa0 hex)
## Booting image at 30008000 ...
Image Name: tekkamanninja
Created: 2007-09-25 9:28:11 UTC
Image Type: ARM Linux Kernel Image (uncompressed)
Data Size: 1727072 Bytes = 1.6 MB
Load Address: 30008000
Entry Point: 30008040
Verifying Checksum ... OK
XIP Kernel Image ... OK
Starting kernel ...
Uncompressing Linux................................................................................................................ done, booting the kernel.
Linux version 2.6.22.2 () (gcc version 4.1.0) #5 Tue Sep 25 15:43:11 CST 2007
CPU: ARM920T [41129200] revision 0 (ARMv4T), cr=c0007177
Machine: Tekkaman2410
Memory policy: ECC disabled, Data cache writeback
CPU S3C2410A (id 0x32410002)
S3C2410: core 202.800 MHz, memory 101.400 MHz, peripheral 50.700 MHz
S3C24XX Clocks, (c) 2004 Simtec Electronics
CLOCK: Slow mode (1.500 MHz), fast, MPLL on, UPLL on
CPU0: D VIVT write-back cache
CPU0: I cache: 16384 bytes, associativity 64, 32 byte lines, 8 sets
CPU0: D cache: 16384 bytes, associativity 64, 32 byte lines, 8 sets
Built 1 zonelists. Total pages: 16256
Kernel command line: root=/dev/nfs rw nfsroot=192.168.1.22:/home/tekkaman/working/rootfs ip=192.168.1.2:192.168.1.22::255.255.255.0 console=ttySAC0,115200 init=/linuxrc mem=64M
irq: clearing pending ext status 00000100
irq: clearing subpending status 00000002
(以下略)