DM9000 uboot驱动分析
来源:互联网 发布:淘宝官方店有假货吗 编辑:程序博客网 时间:2024/04/28 14:16
今天看了一下DM9000,下面对其工作原理及驱动程序进行分析。
DM9000是一款简单的网卡芯片,内部实现MAC && PHY,阅读芯片手册和原理图应该明白DM9000的寄存器基址,基本寄存器的功能。在2440中不同的片选有不同的地址空间(不明白的搜ngcs),加上DM9000内部的0x300便宜就形成了DM9000的寄存器地址。
几个要点:
1、DM9000寄存器访问。
以DM9000_iow(DM9000_NCR, NCR_RST)为例,向NCR寄存器写入NCR_RST值,跟踪代码发现其实现方法为:(#define DM9000_outb(d,r) ( *(volatile u8 *)r = d ))
static voidDM9000_iow(int reg, u8 value){DM9000_outb(reg, DM9000_IO);DM9000_outb(value, DM9000_DATA);}
向IO中写入寄存器地址,向DATA中写入数据。IO为DM9000基址,DATA为其后4字节。
上面是写寄存器的操作,读寄存器类似:
static u8DM9000_ior(int reg){DM9000_outb(reg, DM9000_IO);return DM9000_inb(DM9000_DATA);}
向IO中写入寄存器地址,读出DATA中的值即可。
注:其实上面的这种操作是以硬件连线为基础的,如果硬件没有按照常规的连接方式,DM9000的读写引脚没有与2440的读写引脚相连那么我们就得使用电平模拟的方式了(知道就好,这么费力不讨好的事情是没人做的,有时候想想都觉得费劲)。
2、PHY寄存器的访问
通过读芯片手册可以明白PHY寄存器是不能直接访问的,我们通过MAC中的相关寄存器来访问PHY寄存器。
2.1:写
1,将PHY的寄存器地址写入EPAR(EEPROM && PHY ADDRESS REGISTER);
2,将数据写入EPDRL && EPDRH(EEPROM && PHY DATA REGISTER);
3,写EPCR(EEPROM && PHY CONTROL REGISTER)为0xa;注意清0哦!
2.2:读
1,将PHY的寄存器地址写入EPAR(EEPROM && PHY ADDRESS REGISTER);
2,写EPCR(EEPROM && PHY CONTROL REGISTER)为0xc;注意清0哦!
3,从EPDRL && EPDRH(EEPROM && PHY DATA REGISTER)读出数据;
DM9000对应的驱动程序对应于uboot目录下的drivers/dm9000x.c和dm9000x.h。实现的主要功能函数包括,eth_init,eth_send,eth_rx,eth_halt。
eth_init主要实现的功能包括:
dm9000_reset(); //复位就是寄存器赋值dm9000_probe(); //探测就是看看ID/* NIC Type: FASTETHER, HOMERUN, LONGRUN */identify_nic(); //对PHY的判断,用处没看到,可能有用,填充了boardinfo结构体 /* GPIO0 on pre-activate PHY */DM9000_iow(DM9000_GPR, 0x00);/*REG_1F bit0 activate phyxcer */ //本人觉得可以去掉,还没在板子上验证。/* Set PHY */set_PHY_mode(); //设置自适应模式,激活PHY /*以下是对寄存器的一些设置好些都是默认值,对照手册看一下就行,明白的就明白了,不明白的你也别较真儿*//* Program operating register */DM9000_iow(DM9000_NCR, 0x0);/* only intern phy supported by now */DM9000_iow(DM9000_TCR, 0);/* TX Polling clear */DM9000_iow(DM9000_BPTR, 0x3f);/* Less 3Kb, 200us */DM9000_iow(DM9000_FCTR, FCTR_HWOT(3) | FCTR_LWOT(8));/* Flow Control : High/Low Water */DM9000_iow(DM9000_FCR, 0x0);/* SH FIXME: This looks strange! Flow Control */DM9000_iow(DM9000_SMCR, 0);/* Special Mode */DM9000_iow(DM9000_NSR, NSR_WAKEST | NSR_TX2END | NSR_TX1END);/* clear TX status */DM9000_iow(DM9000_ISR, 0x0f);/* Clear interrupt status *//*下面是MAC地址相关的东西,跟环境变量有关系*//* Set Node address *///HJ_start /* www.embedsky.net */char *tmp = getenv("ethaddr");char *end;for (i = 0; i < 6; i++){bd->bi_enetaddr[i] = tmp ? simple_strtoul(tmp, &end, 16) : 0;if(tmp)tmp = (*end) ? end+1 : end;}//HJ_end /* www.embedsky.net */printf("MAC: %02x:%02x:%02x:%02x:%02x:%02x\n", bd->bi_enetaddr[0], bd->bi_enetaddr[1], bd->bi_enetaddr[2], bd->bi_enetaddr[3], bd->bi_enetaddr[4], bd->bi_enetaddr[5]);for (i = 0, oft = 0x10; i < 6; i++, oft++)DM9000_iow(oft, bd->bi_enetaddr[i]);for (i = 0, oft = 0x16; i < 8; i++, oft++)DM9000_iow(oft, 0xff); //核心就是这几句,往寄存器写东西/* read back mac, just to be sure */for (i = 0, oft = 0x10; i < 6; i++, oft++)DM9000_DBG("%02x:", DM9000_ior(oft));DM9000_DBG("\n");/*MAC地址部分结束*//* Activate DM9000 */DM9000_iow(DM9000_RCR, RCR_DIS_LONG | RCR_DIS_CRC | RCR_RXEN);/* RX enable */DM9000_iow(DM9000_IMR, IMR_PAR);/* Enable TX/RX interrupt mask */
eth_send:(参数为包起始地址,数据长度)
DM9000的发送过程比较简单,传递包长度,填充数据,时能发送就可以。
* Move data to DM9000 TX RAM */data_ptr = (char *) packet;DM9000_outb(DM9000_MWCMD, DM9000_IO);#ifdef CONFIG_DM9000_USE_8BIT/* Byte mode */for (i = 0; i < length; i++)DM9000_outb((data_ptr[i] & 0xff), DM9000_DATA);#endif #ifdef CONFIG_DM9000_USE_16BITtmplen = (length + 1) / 2;for (i = 0; i < tmplen; i++)DM9000_outw(((u16 *) data_ptr)[i], DM9000_DATA);#endif #ifdef CONFIG_DM9000_USE_32BITtmplen = (length + 3) / 4;for (i = 0; i < tmplen; i++)DM9000_outl(((u32 *) data_ptr)[i], DM9000_DATA);#endif 填充数据分为三种数据宽度模式/* Set TX length to DM9000 */DM9000_iow(DM9000_TXPLL, length & 0xff);DM9000_iow(DM9000_TXPLH, (length >> 8) & 0xff); 写寄存器长度/* Issue TX polling command */DM9000_iow(DM9000_TCR, TCR_TXREQ);/* Cleared after TX complete */ //使能发送/* wait for end of transmission */tmo = get_timer(0) + 5 * CFG_HZ;while (DM9000_ior(DM9000_TCR) & TCR_TXREQ) {if (get_timer(0) >= tmo) {printf("transmission timeout\n");break;}} //超时检查
eth_rx:
/* Check packet ready or not */DM9000_ior(DM9000_MRCMDX);/* Dummy read */ //这里写成DM9000_outb(DM9000_MRCMDX, DM9000_IO);更加合适,因为包格式第一个字节 01,下面的注释也说这个值不是0就是1。再说了这就是判断包呢,判断第一个字节就行了。rxbyte = DM9000_inb(DM9000_DATA);/* Got most updated data */if (rxbyte == 0)return 0;/* Status check: this byte must be 0 or 1 */if (rxbyte > 1) {DM9000_iow(DM9000_RCR, 0x00);/* Stop Device */DM9000_iow(DM9000_ISR, 0x80);/* Stop INT request */DM9000_DBG("rx status check: %d\n", rxbyte);}DM9000_DBG("receiving packet\n");/* A packet ready now & Get status/length */DM9000_outb(DM9000_MRCMD, DM9000_IO); /*然后就读就行了有三种模式,先读前四个字节,状态和长度,然后是数据*/#ifdef CONFIG_DM9000_USE_8BITRxStatus = DM9000_inb(DM9000_DATA) + (DM9000_inb(DM9000_DATA) << 8);RxLen = DM9000_inb(DM9000_DATA) + (DM9000_inb(DM9000_DATA) << 8);#endif /* */#ifdef CONFIG_DM9000_USE_16BITRxStatus = DM9000_inw(DM9000_DATA);RxLen = DM9000_inw(DM9000_DATA);#endif /* */#ifdef CONFIG_DM9000_USE_32BITtmpdata = DM9000_inl(DM9000_DATA);RxStatus = tmpdata;RxLen = tmpdata >> 16;#endif /* */DM9000_DBG("rx status: 0x%04x rx len: %d\n", RxStatus, RxLen);/* Move data from DM9000 *//* Read received packet from RX SRAM */#ifdef CONFIG_DM9000_USE_8BITfor (i = 0; i < RxLen; i++)rdptr[i] = DM9000_inb(DM9000_DATA);#endif /* */#ifdef CONFIG_DM9000_USE_16BITtmplen = (RxLen + 1) / 2;for (i = 0; i < tmplen; i++)((u16 *) rdptr)[i] = DM9000_inw(DM9000_DATA);#endif /* */#ifdef CONFIG_DM9000_USE_32BITtmplen = (RxLen + 3) / 4;for (i = 0; i < tmplen; i++)((u32 *) rdptr)[i] = DM9000_inl(DM9000_DATA);#endif /* */if ((RxStatus & 0xbf00) || (RxLen < 0x40) || (RxLen > DM9000_PKT_MAX)) {if (RxStatus & 0x100) {printf("rx fifo error\n");}if (RxStatus & 0x200) {printf("rx crc error\n");}if (RxStatus & 0x8000) {printf("rx length error\n");}if (RxLen > DM9000_PKT_MAX) {printf("rx length too big\n");dm9000_reset();}} else {/* Pass to upper layer */DM9000_DBG("passing packet to upper layer\n");NetReceive(NetRxPackets[0], RxLen); //传到上层这个函数还没分析应该就是包重组return RxLen;}
eth_halt:
//断电一个,禁止一堆。
phy_write(0, 0x8000);/* PHY RESET */DM9000_iow(DM9000_GPR, 0x01);/* Power-Down PHY */DM9000_iow(DM9000_IMR, 0x80);/* Disable all interrupt */DM9000_iow(DM9000_RCR, 0x00);/* Disable RX */
- DM9000 uboot驱动分析
- XFD6410 uboot支持DM9000驱动
- OK6410 uboot 网卡驱动 DM9000
- linux Dm9000 驱动分析
- DM9000网卡驱动分析
- dm9000驱动分析
- DM9000网卡驱动分析
- DM9000网卡驱动分析
- mini2440 DM9000驱动分析
- dm9000驱动分析
- 【驱动】DM9000网卡驱动分析
- 移植DM9000网卡驱动到uboot
- uboot 添加 DM9000支持,作为uboot移植网卡驱动参考
- dm9000驱动代码流程分析
- DM9000驱动分析之初始化
- DM9000驱动分析之发送
- DM9000网卡驱动深度分析
- 【linux驱动分析】之dm9000驱动分析
- CLOB字段的插入与更新
- Android/java面试题-总有你不懂的!
- EXCLE指定单元格复制,采用cells(行号,列号)引用
- 网络概述与常见的网络传输介质
- db2 USER MAPPING, CREATE SERVER机NICKNAME
- DM9000 uboot驱动分析
- http协议:响应码
- 红黑树
- xna中加入Mercury粒子系统
- java中堆(heap)和堆栈(stack)有什么区别
- POJ 2949
- 补习计算机网络和操作系统
- 章二.Windows操作驱动的基本概念(下)
- SQL SERVER 移除分区函数和分区方案