?lang_form? ?lang_select? ?lang_submit? ?lang_endform?
{HEADER END}
{FILE START}

library

?curdirlinks? - Rev 6

?prevdifflink? - Blame - ?getfile?

/*! \file rtl8019.c \brief Realtek RTL8019AS Ethernet Interface Driver. */
//*****************************************************************************
//
// File Name    : 'rtl8019.c'
// Title                : Realtek RTL8019AS Ethernet Interface Driver
// Author               : Pascal Stang
// Created              : 7/6/2004
// Revised              : 10/1/2005
// Version              : 0.1
// Target MCU   : Atmel AVR series
// Editor Tabs  : 4
//
// Based in part on code by Louis Beaudoin (www.embedded-creations.com).
// Thanks to Adam Dunkels and Louis Beaudoin for providing the initial
// structure in which to write this driver.
//*****************************************************************************

#include "global.h"
#include "timer.h"
#include "rprintf.h"

#include "rtl8019.h"

// include configuration
#include "rtl8019conf.h"

// pointers to locations in the RTL8019 receive buffer
static unsigned char NextPage;                          // page pointer to next Rx packet
static unsigned int CurrentRetreiveAddress;     // DMA address for read Rx packet location


void nicInit(void)
{
        rtl8019Init();
}

void nicSend(unsigned int len, unsigned char* packet)
{
        rtl8019BeginPacketSend(len);
        rtl8019SendPacketData(packet, len);
        rtl8019EndPacketSend();
}

unsigned int nicPoll(unsigned int maxlen, unsigned char* packet)
{
        unsigned int packetLength;
        
        packetLength = rtl8019BeginPacketRetreive();

        // if there's no packet or an error - exit without ending the operation
        if( !packetLength )
                return 0;

        // drop anything too big for the buffer
        if( packetLength > maxlen )
        {
                rtl8019EndPacketRetreive();
                return 0;
        }
        
        // copy the packet data into the packet buffer
        rtl8019RetreivePacketData( packet, packetLength );
        rtl8019EndPacketRetreive();
                
        return packetLength;
}

void nicGetMacAddress(u08* macaddr)
{
        u08 tempCR;
        // switch register pages
        tempCR = rtl8019Read(CR);
        rtl8019Write(CR,tempCR|PS0);
        // read MAC address registers
        *macaddr++ = rtl8019Read(PAR0);
        *macaddr++ = rtl8019Read(PAR1);
        *macaddr++ = rtl8019Read(PAR2);
        *macaddr++ = rtl8019Read(PAR3);
        *macaddr++ = rtl8019Read(PAR4);
        *macaddr++ = rtl8019Read(PAR5);
        // switch register pages back
        rtl8019Write(CR,tempCR);
}

void nicSetMacAddress(u08* macaddr)
{
        u08 tempCR;
        // switch register pages
        tempCR = rtl8019Read(CR);
        rtl8019Write(CR,tempCR|PS0);
        // write MAC address registers
        rtl8019Write(PAR0, *macaddr++);
        rtl8019Write(PAR1, *macaddr++);
        rtl8019Write(PAR2, *macaddr++);
        rtl8019Write(PAR3, *macaddr++);
        rtl8019Write(PAR4, *macaddr++);
        rtl8019Write(PAR5, *macaddr++);
        // switch register pages back
        rtl8019Write(CR,tempCR);
}

void nicRegDump(void)
{
        rtl8019RegDump();
}


void rtl8019SetupPorts(void)
{
#if NIC_CONNECTION == MEMORY_MAPPED
        // enable external SRAM interface - no wait states
        sbi(MCUCR, SRE);
//      sbi(MCUCR, SRW10);
//      sbi(XMCRA, SRW00);
//      sbi(XMCRA, SRW01);
//      sbi(XMCRA, SRW11);
#else
    // make the address port output
        RTL8019_ADDRESS_DDR |= RTL8019_ADDRESS_MASK;
    // make the data port input with pull-ups
    RTL8019_DATA_PORT = 0xFF;

        // initialize the control port read and write pins to de-asserted
        RTL8019_CONTROL_DDR |= (1<<RTL8019_CONTROL_READPIN);
    RTL8019_CONTROL_DDR |= (1<<RTL8019_CONTROL_WRITEPIN);
        // set the read and write pins to output
        RTL8019_CONTROL_PORT |= (1<<RTL8019_CONTROL_READPIN);
        RTL8019_CONTROL_PORT |= (1<<RTL8019_CONTROL_WRITEPIN);
#endif
        // set reset pin to output
        sbi(RTL8019_RESET_DDR, RTL8019_RESET_PIN);
}


#if NIC_CONNECTION == MEMORY_MAPPED
inline void rtl8019Write(u08 address, u08 data)
{
        *(volatile u08*)(RTL8019_MEMORY_MAPPED_OFFSET + address) = data;
}
#else
void rtl8019Write(unsigned char address, unsigned char data)
{
        // assert the address
        RTL8019_ADDRESS_PORT = address | (RTL8019_ADDRESS_PORT&~RTL8019_ADDRESS_MASK);
        // set data bus as output and place data on bus
        RTL8019_DATA_DDR = 0xFF;
        RTL8019_DATA_PORT = data;
        // clock write pin
        cbi(RTL8019_CONTROL_PORT, RTL8019_CONTROL_WRITEPIN);
        nop();
        nop();
        sbi(RTL8019_CONTROL_PORT, RTL8019_CONTROL_WRITEPIN);
        // set data port back to input with pullups enabled
    RTL8019_DATA_DDR = 0x00;
    RTL8019_DATA_PORT = 0xFF;
}
#endif


#if NIC_CONNECTION == MEMORY_MAPPED
inline u08 ax88796Read(u08 address)
{
        return *(volatile u08*)(RTL8019_MEMORY_MAPPED_OFFSET + address);
}
#else
unsigned char rtl8019Read(unsigned char address)
{
        unsigned char data;
   
        // assert the address
        RTL8019_ADDRESS_PORT = address | (RTL8019_ADDRESS_PORT&~RTL8019_ADDRESS_MASK);
        // assert read
        cbi(RTL8019_CONTROL_PORT, RTL8019_CONTROL_READPIN);
        nop();
        nop();
        // read in the data
        data = RTL8019_DATA_PIN;
        // negate read
        sbi(RTL8019_CONTROL_PORT, RTL8019_CONTROL_READPIN);
        // return data
        return data;
}
#endif                       


void rtl8019Init(void)
{
        // setup I/O ports
        rtl8019SetupPorts();
        
        // do a hard reset
        sbi(RTL8019_RESET_PORT, RTL8019_RESET_PIN);
        delay_ms(10);
        cbi(RTL8019_RESET_PORT, RTL8019_RESET_PIN);

        // clear interrupt state
        rtl8019Write( ISR, rtl8019Read(ISR) );
        delay_ms(50);

        // switch to page 3 to load config registers
        rtl8019Write(CR, (PS0|PS1|RD2|STOP));

        // disable EEPROM write protect of config registers
        rtl8019Write(RTL_EECR, (EEM1|EEM0));

    // set network type to 10 Base-T link test
        rtl8019Write(CONFIG2, 0x20);

    // disable powerdown and sleep
        rtl8019Write(CONFIG3, 0);
        delay_ms(255);

    // reenable EEPROM write protect
        rtl8019Write(RTL_EECR, 0);

    // go back to page 0, stop NIC, abort DMA
        rtl8019Write(CR, (RD2|STOP));
        delay_ms(2);                                    // wait for traffic to complete
        rtl8019Write(DCR, DCR_INIT);
        rtl8019Write(RBCR0,0x00);
        rtl8019Write(RBCR1,0x00);
        rtl8019Write(RCR, AB);
        rtl8019Write(TPSR, TXSTART_INIT);
        rtl8019Write(TCR, LB0);
        rtl8019Write(PSTART, RXSTART_INIT);
        rtl8019Write(BNRY, RXSTART_INIT);
        rtl8019Write(PSTOP, RXSTOP_INIT);
        rtl8019Write(CR, (PS0|RD2|STOP));       // switch to page 1
        delay_ms(2);
        rtl8019Write(CPR, RXSTART_INIT);
        
        // set MAC address
        rtl8019Write(PAR0, RTL8019_MAC0);
        rtl8019Write(PAR1, RTL8019_MAC1);
        rtl8019Write(PAR2, RTL8019_MAC2);
        rtl8019Write(PAR3, RTL8019_MAC3);
        rtl8019Write(PAR4, RTL8019_MAC4);
        rtl8019Write(PAR5, RTL8019_MAC5);
    
        // initialize sequence per NE2000 spec
        rtl8019Write(CR, (RD2|STOP));
        rtl8019Write(DCR, DCR_INIT);
        rtl8019Write(CR, (RD2|START));
        rtl8019Write(ISR,0xFF);                 // clear all interrupts
        rtl8019Write(IMR, IMR_INIT);
        rtl8019Write(TCR, TCR_INIT);
        
        rtl8019Write(CR, (RD2|START));  // start the NIC
}


void rtl8019BeginPacketSend(unsigned int packetLength)
{
        unsigned int sendPacketLength;
        sendPacketLength = (packetLength>=ETHERNET_MIN_PACKET_LENGTH)?
                                                (packetLength):ETHERNET_MIN_PACKET_LENGTH;
        
        //start the NIC
        rtl8019Write(CR, (RD2|START));
        
        // still transmitting a packet - wait for it to finish
        while( rtl8019Read(CR) & TXP );

        // load beginning page for transmit buffer
        rtl8019Write(TPSR,TXSTART_INIT);
        
        // set start address for remote DMA operation
        rtl8019Write(RSAR0,0x00);
        rtl8019Write(RSAR1,0x40);
        
        // clear the packet stored interrupt
        rtl8019Write(ISR,PTX);

        // load data byte count for remote DMA
        rtl8019Write(RBCR0, (unsigned char)(packetLength));
        rtl8019Write(RBCR1, (unsigned char)(packetLength>>8));

        rtl8019Write(TBCR0, (unsigned char)(sendPacketLength));
        rtl8019Write(TBCR1, (unsigned char)((sendPacketLength)>>8));
        
        // do remote write operation
        rtl8019Write(CR,(RD1|START));
}


void rtl8019SendPacketData(unsigned char *localBuffer, unsigned int length)
{
        unsigned int i;
        
        // write data to DMA port
        for(i=0;i<length;i++)
                rtl8019Write(RDMAPORT, localBuffer[i]);
}


void rtl8019EndPacketSend(void)
{
        //send the contents of the transmit buffer onto the network
        rtl8019Write(CR,(RD2|TXP));
        // clear the remote DMA interrupt
        rtl8019Write(ISR, RDC);
}


unsigned int rtl8019BeginPacketRetreive(void)
{
        unsigned char i;
        unsigned char bnry;
        
        unsigned char pageheader[4];
        unsigned int rxlen;
        
        // check for and handle an overflow
        rtl8019ProcessInterrupt();
        
        // read CPR from page 1
        rtl8019Write(CR,(PS0|RD2|START));
        i = rtl8019Read(CPR);
        
        // return to page 0
        rtl8019Write(CR,(RD2|START));
        
        // read the boundary register - pointing to the beginning of the packet
        bnry = rtl8019Read(BNRY) ;
        
        // return if there is no packet in the buffer
        if( bnry == i )
                return 0;

        // clear the packet received interrupt flag
        rtl8019Write(ISR, PRX);
        
        // if boundary pointer is invalid
        if( (bnry >= RXSTOP_INIT) || (bnry < RXSTART_INIT) )
        {
                // reset the contents of the buffer and exit
                rtl8019Write(BNRY, RXSTART_INIT);
                rtl8019Write(CR, (PS0|RD2|START));
                rtl8019Write(CPR, RXSTART_INIT);
                rtl8019Write(CR, (RD2|START));
                return 0;
        }

        // initiate DMA to transfer the RTL8019 packet header
        rtl8019Write(RBCR0, 4);
        rtl8019Write(RBCR1, 0);
        rtl8019Write(RSAR0, 0);
        rtl8019Write(RSAR1, bnry);
        rtl8019Write(CR, (RD0|START));
        // transfer packet header
        for(i=0;i<4;i++)
                pageheader[i] = rtl8019Read(RDMAPORT);
        // end the DMA operation
        rtl8019Write(CR, (RD2|START));
        // wait for remote DMA complete
        for(i = 0; i < 20; i++)
                if(rtl8019Read(ISR) & RDC)
                        break;
        rtl8019Write(ISR, RDC);

        rxlen = (pageheader[PKTHEADER_PKTLENH]<<8) + pageheader[PKTHEADER_PKTLENL];
        NextPage = pageheader[PKTHEADER_NEXTPAGE];
        
        CurrentRetreiveAddress = (bnry<<8) + 4;
        
        // if the NextPage pointer is invalid, the packet is not ready yet - exit
        if( (NextPage >= RXSTOP_INIT) || (NextPage < RXSTART_INIT) )
                return 0;
    
        return rxlen-4;
}


void rtl8019RetreivePacketData(unsigned char * localBuffer, unsigned int length)
{
        unsigned int i;
        
        // initiate DMA to transfer the data
        rtl8019Write(RBCR0, (unsigned char)length);
        rtl8019Write(RBCR1, (unsigned char)(length>>8));
        rtl8019Write(RSAR0, (unsigned char)CurrentRetreiveAddress);
        rtl8019Write(RSAR1, (unsigned char)(CurrentRetreiveAddress>>8));
        rtl8019Write(CR, (RD0|START));
        // transfer packet data
        for(i=0;i<length;i++)
                localBuffer[i] = rtl8019Read(RDMAPORT);
        // end the DMA operation
        rtl8019Write(CR, (RD2|START));
        // wait for remote DMA complete
        for(i=0; i<20; i++)
                if(rtl8019Read(ISR) & RDC)
                        break;
        rtl8019Write(ISR, RDC);
        // keep track of current address
    CurrentRetreiveAddress += length;
    if( CurrentRetreiveAddress >= 0x6000 )
        CurrentRetreiveAddress = CurrentRetreiveAddress - (0x6000-0x4600) ;
}


void rtl8019EndPacketRetreive(void)
{
        unsigned char i;

        // end the DMA operation
        rtl8019Write(CR, (RD2|START));
        // wait for remote DMA complete
        for(i=0; i<20; i++)
                if(rtl8019Read(ISR) & RDC)
                        break;
        rtl8019Write(ISR, RDC);

        // set the boundary register to point to the start of the next packet
        rtl8019Write(BNRY, NextPage);
}


void rtl8019ProcessInterrupt(void)
{
        unsigned char byte = rtl8019Read(ISR);
        
        if( byte & OVW )
                rtl8019ReceiveOverflowRecover();
}

void rtl8019ReceiveOverflowRecover(void)
{
        unsigned char data_L, resend;   

        data_L = rtl8019Read(CR);
        rtl8019Write(CR, 0x21);
        delay_ms(2);
        rtl8019Write(RBCR0, 0x00);
        rtl8019Write(RBCR1, 0x00);
        if(!(data_L & 0x04))
                resend = 0;
        else if(data_L & 0x04)
        {
                data_L = rtl8019Read(ISR);
                if((data_L & 0x02) || (data_L & 0x08))
                resend = 0;
            else
                resend = 1;
        }
        
        rtl8019Write(TCR, 0x02);
        rtl8019Write(CR, 0x22);
        rtl8019Write(BNRY, RXSTART_INIT);
        rtl8019Write(CR, 0x62);
        rtl8019Write(CPR, RXSTART_INIT);
        rtl8019Write(CR, 0x22);
        rtl8019Write(ISR, 0x10);
        rtl8019Write(TCR, TCR_INIT);
        
    if(resend)
        rtl8019Write(CR, 0x26);

    rtl8019Write(ISR, 0xFF);
}


void rtl8019RegDump(void)
{
//      unsigned char result;
//      result = rtl8019Read(TR);
        
//      rprintf("Media State: ");
//      if(!(result & AUTOD))
//              rprintf("Autonegotiation\r\n");
//      else if(result & RST_B)
//              rprintf("PHY in Reset   \r\n");
//      else if(!(result & RST_10B))
//              rprintf("10BASE-T       \r\n");
//      else if(!(result & RST_TXB))
//              rprintf("100BASE-T      \r\n");
                                
        //rprintf("TR regsiter      : %x\r\n",result);
        //result = read_mii(0x10,0);
        //rprintf("MII regsiter 0x10: %x\r\n",result);

        rprintf("Page0: CR  BNRY PSR PST ISR TSR RSR MMR TR  GPI\r\n");
        rprintfProgStrM("       ");
        rprintfu08(rtl8019Read(CR));
        rprintfProgStrM("  ");
        rprintfu08(rtl8019Read(BNRY));
        rprintfProgStrM("   ");
        rprintfu08(rtl8019Read(PSTART));
        rprintfProgStrM("  ");
        rprintfu08(rtl8019Read(PSTOP));
        rprintfProgStrM("  ");
        rprintfu08(rtl8019Read(ISR));
        rprintfProgStrM("  ");
        rprintfu08(rtl8019Read(TSR));
        rprintfProgStrM("  ");
        rprintfu08(rtl8019Read(RSR));
        rprintfProgStrM("  ");
//      rprintfu08(rtl8019Read(MEMR));
        rprintfProgStrM("  ");
//      rprintfu08(rtl8019Read(TR));
        rprintfProgStrM("  ");
//      rprintfu08(rtl8019Read(GPI));
        rprintfCRLF();

        rtl8019Write(CR,rtl8019Read(CR)|PS0);

        rprintf("Page1: CR  PAR    CPR\r\n");
        rprintfProgStrM("       ");
        rprintfu08(rtl8019Read(CR));
        rprintfProgStrM("  ");
        rprintfChar(rtl8019Read(PAR0));
        rprintfChar(rtl8019Read(PAR1));
        rprintfChar(rtl8019Read(PAR2));
        rprintfChar(rtl8019Read(PAR3));
        rprintfChar(rtl8019Read(PAR4));
        rprintfChar(rtl8019Read(PAR5));
        rprintfProgStrM(" ");
        rprintfu08(rtl8019Read(CPR));
        
        rtl8019Write(CR,rtl8019Read(CR)&~PS0);

        delay_ms(25);
}

{FILE END}
{FOOTER START}

Powered by WebSVN v2.8.3