;*************************************************************************** ; ; File Name :'dm9000a.asm" ; Title :Davicom DM9000A Driver ; Date :2007.04.02. ; Version :1.0.0 ; Support telephone :+36-70-333-4034, old: +36-30-9541-658 VFX ; Support fax : ; Support Email :info@vfx.hu ; Target MCU :AVR ; ;*************************************************************************** ; D E S C R I P T I O N ; ; Davicom DM9000 ISA NIC fast Ethernet driver for AVR ; Based on "A Davicom DM9000A/DM9010 ISA NIC fast Ethernet driver for Linux" ; .equ ADR_LANS = 0x3FEF ;LAN command .equ ADR_LANI = 0x3FF0 ;DM9000A Index .equ ADR_LAND = 0x3FFF ;DM9000A Data ; ;*************************************************************************** ; M O D I F I C A T I O N H I S T O R Y ; ; ; rev. date who why ; ---- ---------- --- ------------------------------------ ; 0.01 2007.04.02 VFX Creation ; ;************************************************************************** ;* Hardware Def. ; DM9000A Ethernet .equ DM9000_ID = 0x90000A46 .equ DM9000_PKT_MAX = 1536 ;Received packet max size .equ DM9000_PKT_RDY = 0x01 ;Packet ready to receive ; although the registers are 16 bit, they are 32-bit aligned. .equ DM9000_NCR = 0x00 .equ DM9000_NSR = 0x01 .equ DM9000_TCR = 0x02 .equ DM9000_TSR1 = 0x03 .equ DM9000_TSR2 = 0x04 .equ DM9000_RCR = 0x05 .equ DM9000_RSR = 0x06 .equ DM9000_ROCR = 0x07 .equ DM9000_BPTR = 0x08 .equ DM9000_FCTR = 0x09 .equ DM9000_FCR = 0x0A .equ DM9000_EPCR = 0x0B .equ DM9000_EPAR = 0x0C .equ DM9000_EPDRL = 0x0D .equ DM9000_EPDRH = 0x0E .equ DM9000_WCR = 0x0F .equ DM9000_PAR = 0x10 .equ DM9000_MAR = 0x16 .equ DM9000_GPCR = 0x1e .equ DM9000_GPR = 0x1f .equ DM9000_TRPAL = 0x22 .equ DM9000_TRPAH = 0x23 .equ DM9000_RWPAL = 0x24 .equ DM9000_RWPAH = 0x25 .equ DM9000_VIDL = 0x28 .equ DM9000_VIDH = 0x29 .equ DM9000_PIDL = 0x2A .equ DM9000_PIDH = 0x2B .equ DM9000_CHIPR = 0x2C .equ DM9000_SMCR = 0x2F .equ DM9000_PHY = 0x40 ;PHY address 0x01 .equ DM9000_MRCMDX = 0xF0 .equ DM9000_MRCMD = 0xF2 .equ DM9000_MRRL = 0xF4 .equ DM9000_MRRH = 0xF5 .equ DM9000_MWCMDX = 0xF6 .equ DM9000_MWCMD = 0xF8 .equ DM9000_MWRL = 0xFA .equ DM9000_MWRH = 0xFB .equ DM9000_TXPLL = 0xFC .equ DM9000_TXPLH = 0xFD .equ DM9000_ISR = 0xFE .equ DM9000_IMR = 0xFF .equ NCR_EXT_PHY = (1<<7) .equ NCR_WAKEEN = (1<<6) .equ NCR_FCOL = (1<<4) .equ NCR_FDX = (1<<3) .equ NCR_LBK = (3<<1) .equ NCR_RST = (1<<0) .equ NSR_SPEED = (1<<7) .equ NSR_LINKST = (1<<6) .equ NSR_WAKEST = (1<<5) .equ NSR_TX2END = (1<<3) .equ NSR_TX1END = (1<<2) .equ NSR_RXOV = (1<<1) .equ TCR_TJDIS = (1<<6) .equ TCR_EXCECM = (1<<5) .equ TCR_PAD_DIS2 = (1<<4) .equ TCR_CRC_DIS2 = (1<<3) .equ TCR_PAD_DIS1 = (1<<2) .equ TCR_CRC_DIS1 = (1<<1) .equ TCR_TXREQ = (1<<0) .equ TSR_TJTO = (1<<7) .equ TSR_LC = (1<<6) .equ TSR_NC = (1<<5) .equ TSR_LCOL = (1<<4) .equ TSR_COL = (1<<3) .equ TSR_EC = (1<<2) .equ RCR_WTDIS = (1<<6) .equ RCR_DIS_LONG = (1<<5) .equ RCR_DIS_CRC = (1<<4) .equ RCR_ALL = (1<<3) .equ RCR_RUNT = (1<<2) .equ RCR_PRMSC = (1<<1) .equ RCR_RXEN = (1<<0) .equ RSR_RF = (1<<7) .equ RSR_MF = (1<<6) .equ RSR_LCS = (1<<5) .equ RSR_RWTO = (1<<4) .equ RSR_PLE = (1<<3) .equ RSR_AE = (1<<2) .equ RSR_CE = (1<<1) .equ RSR_FOE = (1<<0) ;.equ FCTR_HWOT(ot) (( ot & 0xf ) << 4 ) ;.equ FCTR_LWOT(ot) ( ot & 0xf ) .equ IMR_LNKCHGI = (1<<5) .equ IMR_UDRUNI = (1<<4) .equ IMR_PAR = (1<<7) .equ IMR_ROOI = (1<<3) .equ IMR_ROI = (1<<2) .equ IMR_PTI = (1<<1) .equ IMR_PRI = (1<<0) .equ ISR_LNKCHG = (1<<5) .equ ISR_UDRUN = (1<<4) .equ ISR_ROOS = (1<<3) .equ ISR_ROS = (1<<2) .equ ISR_PTS = (1<<1) .equ ISR_PRS = (1<<0) .equ ISR_CLR_STATUS = (ISR_ROOS | ISR_ROS | ISR_PTS | ISR_PRS) .equ EPCR_REEP = (1<<5) .equ EPCR_WEP = (1<<4) .equ EPCR_EPOS = (1<<3) .equ EPCR_ERPRR = (1<<2) .equ EPCR_ERPRW = (1<<1) .equ EPCR_ERRE = (1<<0) .equ GPCR_GEP_CNTL = (1<<0) ; Board/System/Debug information/definition .equ DM9801_NOISE_FLOOR = 0x08 .equ DM9802_NOISE_FLOOR = 0x05 ;DM9000_PHY_mode .equ DM9000_10MHD = 0x00 .equ DM9000_100MHD = 0x01 .equ DM9000_10MFD = 0x04 .equ DM9000_100MFD = 0x05 .equ DM9000_AUTO = 0x08 .equ DM9000_1M_HPNA = 0x10 ;DM9000_NIC_TYPE .equ FASTETHER_NIC = 0 .equ HOMERUN_NIC = 1 .equ LONGRUN_NIC = 2 ;***************************************************************************** ; ; Ethernet constants ; ;**************************************************************************** .equ ETHERNET_MIN_PACKET_LENGTH = 0x3C .equ ETHERNET_HEADER_LENGTH = 0x0E .equ IP_TCP_HEADER_LENGTH = 40 .equ TOTAL_HEADER_LENGTH = IP_TCP_HEADER_LENGTH+ETHERNET_HEADER_LENGTH ; LANBUFSIZE: The size of the buffer that holds incoming and outgoing packets. .equ LANBUFSIZE = 1564 ;*************************************************************************** .ESEG ; ETHADDR: The Ethernet address ; 48 bit IEEE OUI (Organizationally Unique Identifier) EETHADDR: .db 0xDE,0xD0,0x80,0x00,0x00,0x02 ; ;*************************************************************************** ;**** VARIABLES .DSEG ETHADDR: .byte 6 ;*************************************************************************** ;**** CODE SEG ;*************************************************************************** .CSEG ;************************************************************* ; Read DM9000A register ; ; In: R16 - register index ; ; Out: R16 - read data ; DM9k_ior: sts ADR_LANI,R16 nop lds R16,ADR_LAND ret ;************************************************************* ; Write DM9000A register ; ; In: R16 - register index ; R17 - data ; ; Out: - ; DM9k_iow: sts ADR_LANI,R16 nop sts ADR_LAND,R17 ret ;************************************************************* ; Read a word from phyxcer ; ; In: R16 - PHY register ; ; Out: R19:R18 - read word ; phy_read: ;Fill the phyxcer register into REG_0C ldi R17,DM9000_PHY or R17,R16 ldi R16,DM9000_EPAR rcall DM9k_iow ;Issue phyxcer read command ldi R16,DM9000_EPCR ldi R17,0x0c rcall DM9k_iow call Delay40us ;Wait read complete min. 100us call Delay40us call Delay40us ;Clear phyxcer read command ldi R16,DM9000_EPCR ldi R17,0x00 rcall DM9k_iow ;Read PHY value ldi R16,DM9000_EPDRH rcall DM9k_ior mov R19,R16 ;hi-byte ldi R16,DM9000_EPDRL rcall DM9k_ior mov R18,R16 ;low byte ret ;************************************************************* ; Write a word to phyxcer ; ; In: R16 - PHY register ; R19:R18 - PHY data ; ; Out: - ; phy_write: ;Fill the phyxcer register into REG_0C ldi R17,DM9000_PHY or R17,R16 ldi R16,DM9000_EPAR rcall DM9k_iow ;Fill the written data into REG_0D & REG_0E ldi R16,DM9000_EPDRL mov R17,R18 rcall DM9k_iow ldi R16,DM9000_EPDRH mov R17,R19 rcall DM9k_iow ;Issue phyxcer write command ldi R16,DM9000_EPCR ldi R17,0xa rcall DM9k_iow ldi R16,1 ;Wait write complete cc. 500us call Wait1ms ; Clear phyxcer write command ldi R16,DM9000_EPCR ldi R17,0x00 rcall DM9k_iow ret ;************************************************************* ; Read a word data from SROM ; ; In: R16 - offset ; ; Out: R19:R18 - read word ; ; CONFIG_DM9000_HAVE_EEPROM ; read_srom_word: mov R17,R16 ldi R16,DM9000_EPAR rcall DM9k_iow ldi R16,DM9000_EPCR ldi R17,0x4 rcall DM9k_iow ldi R16,1 ;Wait write complete cc. 200us call Wait1ms ldi R16,DM9000_EPCR ldi R17,0x00 rcall DM9k_iow ldi R16,DM9000_EPDRL rcall DM9k_ior mov R18,R16 ;low byte ldi R16,DM9000_EPDRH rcall DM9k_ior mov R19,R16 ;hi byte ret ;************************************************************* ; Identify NIC type ; ; In: - ; ; Out: R19:R18 - Phy Type ; c = 1 no valid phy ; identify_nic: ldi R16,DM9000_NCR ldi R17,NCR_EXT_PHY rcall DM9k_iow ldi R16,3 rcall phy_read ;R19:R18 Phy data cpi R19,0xb9 brne FastPhy cpi R18,0x00 brne FastPhy sec ;HOMERUN_NIC or LONGRUN_NIC ret FastPhy: ;FASTETHER_NIC; ldi R16,DM9000_NCR ldi R17,0 rcall DM9k_iow clc ret ;************************************************************* ; HW Reset DM9000A ; ; In: - ; ; Out: - ; DM9k_HW_Reset: ldi R16,0 sts ADR_LANS,R16 ;LAN reset active ldi R16,1 call Wait1ms ldi R16,255 sts ADR_LANS,R16 ;LAN reset inactive ldi R16,1 call Wait1ms ret ;************************************************************* ; Search DM9000A ; ; In: - ; ; Out: c = 1 DM9000A notfound ; ; Search and HW reset DM9000A ; DM9k_Probe: ldi R16,DM9000_VIDL rcall DM9k_ior cpi R16,0x46 ;byte1(DM9000_ID) brne NoNetBoard ldi R16,DM9000_VIDH rcall DM9k_ior cpi R16,0x0a ;byte2(DM9000_ID) brne NoNetBoard ldi R16,DM9000_PIDL rcall DM9k_ior cpi R16,0x00 ;byte3(DM9000_ID) brne NoNetBoard ldi R16,DM9000_PIDH rcall DM9k_ior cpi R16,0x90 ;byte4(DM9000_ID) brne NoNetBoard clc ret NoNetBoard: sec ret ;************************************************************* ; Set PHY operationg mode ; ; In: - ; ; Out: - ; PhyMode_10MHD: ldi R18,low(0x21) ;phy_reg4 ldi R19,high(0x21) ldi R20,low(0x0000) ;phy_reg0 ldi R21,high(0x0000) rjmp SetPhy PhyMode_10MFD: ldi R18,low(0x41) ;phy_reg4 ldi R19,high(0x41) ldi R20,low(0x1100) ;phy_reg0 ldi R21,high(0x1100) rjmp SetPhy PhyMode_100MHD: ldi R18,low(0x81) ;phy_reg4 ldi R19,high(0x81) ldi R20,low(0x2000) ;phy_reg0 ldi R21,high(0x2000) rjmp SetPhy PhyMode_100MFD: ldi R18,low(0x101) ;phy_reg4 ldi R19,high(0x101) ldi R20,low(0x3100) ;phy_reg0 ldi R21,high(0x3100) rjmp SetPhy PhyMode_Auto: ldi R18,low(0x01e1) ;phy_reg4 ldi R19,high(0x01e1) ldi R20,low(0x1000) ;phy_reg0 ldi R21,high(0x1000) SetPhy: ldi R16,4 rcall phy_write ;Set PHY media mode ldi R16,0 movw R18,R20 rcall phy_write ;Tmp ;DM9000_iow (dm, DM9000_GPCR, 0x01); // Let GPIO0 output */ ;Enable PHY ldi R16,DM9000_GPR ldi R17,0x00 rcall DM9k_iow ret ;************************************************************* ; General Purpose dm9000 reset routine ; ; In: - ; ; Out: - ; dm9k_reset: ldi R16,DM9000_NCR ldi R17,NCR_RST rcall DM9k_iow ldi R16,1 call Wait1ms ;delay 1ms ret ;************************************************************* ; Initilize dm9000 board ; ; In: - ; ; Out: c = 1 error, board not valid, active ect. ; DM9k_Init: rcall DM9k_HW_Reset ldi R16,DM9000_GPR ;REG_1F bit0 activate phyxcer ldi R17,0x01 rcall DM9k_iow ldi R16,1 call Wait1ms ;delay 500us ldi R16,DM9000_GPR ldi R17,0x00 rcall DM9k_iow ldi R16,2 call Wait1ms ;wait 2ms for PHY power-on ready ;RESET device rcall dm9k_reset rcall DM9k_Probe brcc DM9k_Tovabb rcall DM9k_Probe brcc DM9k_Tovabb ret ;No valid DM900A DM9k_Tovabb: rcall identify_nic ;NIC Type: FASTETHER, HOMERUN, LONGRUN brcc DM9k_Tovabb1 ret ;No valid PHY DM9k_Tovabb1: ldi R16,DM9000_GPR ldi R17,0x00 rcall DM9k_iow rcall PhyMode_Auto ;Set PHY ;Program operating register ;only intern phy supported by now ldi R16,DM9000_NCR ldi R17,0x00 rcall DM9k_iow ;TX Polling clear ldi R16,DM9000_TCR ldi R17,0 rcall DM9k_iow ;Less 3Kb, 200us ldi R16,DM9000_BPTR ldi R17,0x3f rcall DM9k_iow ;Flow Control : High/Low Water ldi R16,DM9000_FCTR ldi R17,0x38 rcall DM9k_iow ;SH FIXME: This looks strange! Flow Control ldi R16,DM9000_FCR ldi R17,0x0 rcall DM9k_iow ;Special Mode ldi R16,DM9000_SMCR ldi R17,0 rcall DM9k_iow ;clear TX status ldi R16,DM9000_NSR ldi R17,NSR_WAKEST | NSR_TX2END | NSR_TX1END rcall DM9k_iow ;Clear interrupt status ldi R16,DM9000_ISR ldi R17,0x0f rcall DM9k_iow ;Set Node address ldi ZL,low(EETHADDR) ;MAC address from EEPROM ldi ZH,high(EETHADDR) call EERead sts ETHADDR+0,R0 mov R17,R0 ldi R16,DM9000_PAR+0 ;Setup our MAC Address rcall DM9k_iow adiw ZL,1 call EERead sts ETHADDR+1,R0 mov R17,R0 ldi R16,DM9000_PAR+1 rcall DM9k_iow adiw ZL,1 call EERead sts ETHADDR+2,R0 mov R17,R0 ldi R16,DM9000_PAR+2 rcall DM9k_iow adiw ZL,1 call EERead sts ETHADDR+3,R0 mov R17,R0 ldi R16,DM9000_PAR+3 rcall DM9k_iow adiw ZL,1 call EERead sts ETHADDR+4,R0 mov R17,R0 ldi R16,DM9000_PAR+4 rcall DM9k_iow adiw ZL,1 call EERead sts ETHADDR+5,R0 mov R17,R0 ldi R16,DM9000_PAR+5 rcall DM9k_iow ;set multicast/broadcast address ldi R16,0x16 ;multicast register ldi R17,0xff ldi R18,8 FillM: rcall DM9k_iow inc R16 dec R18 brne FillM ;Activate DM9000 ;RX enable ldi R16,DM9000_RCR ldi R17,RCR_DIS_LONG | RCR_DIS_CRC | RCR_RXEN rcall DM9k_iow ;Enable TX/RX interrupt mask ldi R16,DM9000_IMR ldi R17,IMR_PAR rcall DM9k_iow clc ret ;************************************************************* ; Stop the interface ; ; In: - ; ; Out: ; ; The interface is stopped when it is brought. ; dm9k_halt: ldi R16,0 ldi R18,low(0x8000) ldi R19,high(0x8000) rcall phy_write ;PHY RESET ldi R16,DM9000_GPR ldi R17,0x01 rcall DM9k_iow ;Power-Down PHY ldi R16,DM9000_IMR ldi R17,0x80 rcall DM9k_iow ;Disable all interrupt ldi R16,DM9000_RCR ldi R17,0x00 rcall DM9k_iow ;Disable RX ret ;************************************************************* ; Hardware start transmission. ; ; In: Y - Packet address ; X - Packet length ; ; Out: ; ;Send a packet to media from the upper layer. ; dm9k_send: ;wait for end of previous transmission ;ide kell majd egy time out kilepes! ldi R16,DM9000_TCR rcall DM9k_ior andi R16,TCR_TXREQ brne dm9k_send ;ide meg varakozas kellhet ;Set TX length to DM9000 ldi R16,DM9000_TXPLL mov R17,XL rcall DM9k_iow ldi R16,DM9000_TXPLH mov R17,XH rcall DM9k_iow ;Move data to DM9000 TX RAM ldi R16,DM9000_MWCMD sts ADR_LANI,R16 movw R0,XL ;save length movw R2,YL ;Byte mode SendBytes: ld R16,Y+ sts ADR_LAND,R16 sbiw XL,1 brne SendBytes movw XL,R0 movw YL,R2 ;Set TX length to DM9000 ldi R16,DM9000_TXPLL mov R17,XL rcall DM9k_iow ldi R16,DM9000_TXPLH mov R17,XH rcall DM9k_iow ;Issue TX polling command ldi R16,DM9000_TCR ldi R17,TCR_TXREQ rcall DM9k_iow ;Cleared after TX complete ret ;************************************************************* ; Received a packet and pass to upper layer ; ; In: Y - Packet address ; ; ; Out: Y - Packet address ; X - Packet length ; c - 0 valid packet ; dm9k_recv: ldi R16,DM9000_ISR ;Got DM9000 interrupt status rcall DM9k_ior ;int_status ldi R17,ISR_PRS and R17,R16 ;R17 - RX status ldi R16,DM9000_ISR rcall DM9k_iow ;Clear Rx ISR status cpi R17,0 breq Exit_Rec ;Received the coming packet ;Received a packet and pass to upper layer ;Check packet ready or not ldi R16,DM9000_MRCMDX rcall DM9k_ior ;Dummy read lds R18,ADR_LAND ;Got most updated data ;R18 - rxbyte ;Status check: this byte must be 0 or 1 cpi R18,DM9000_PKT_RDY+1 brcs StatusOk ;Invalid status ldi R16,DM9000_RCR ldi R17,0x00 rcall DM9k_iow ;Stop Device ldi R16,DM9000_ISR ldi R17,IMR_PAR rcall DM9k_iow ;Stop INT request rjmp Exit_Rec StatusOk: cpi R18,DM9000_PKT_RDY ;if (rxbyte != DM9000_PKT_RDY) return breq ReadyToRead Exit_Rec: clr XL clr XH sec ret ReadyToRead: ;A packet ready now & Get status/length ldi R16,DM9000_MRCMD sts ADR_LANI,R16 ;RxStatus [16 bit] lds R18,ADR_LAND lds R19,ADR_LAND lds XL,ADR_LAND ;RxLen [16 bit] lds XH,ADR_LAND ;Packet Status check clr R0 ;R0 = 0 Good Packet cpi XL,0x40 cpc XH,R0 brcc Good1 inc R0 ;(RxLen < 0x40) Bad Packet received Good1: ldi R16,high(DM9000_PKT_MAX+1) ;(RxLen > DM9000_PKT_MAX) - nalam ez is hiba cpi XL,low(DM9000_PKT_MAX+1) cpc XH,R16 brcs Good2 inc R0 Good2: andi R19,0xbf ;(RxStatus & 0xbf00) breq SkipFalse ;0x100 - rx fifo error ;0x200 - rx crc error ;0x8000 - rx length error False1: inc R0 SkipFalse: tst R0 ;if packet is good -> Move data from DM9000 brne BadPacket ;Move data from DM9000 movw R0,XL movw R2,YL st Y+,R18 st Y+,R19 st Y+,XL st Y+,XH RecCycle: lds R16,ADR_LAND st Y+,R16 sbiw XL,1 brne RecCycle movw YL,R2 movw XL,R0 ;Pass to upper layer clc ret BadPacket: ;need to dump the packet's data lds R16,ADR_LAND push XL push XH call SendChrW pop XH pop XL sbiw Xl,1 brne BadPacket rjmp Exit_Rec