www.pudn.com > Test_rtl8019_SRAM.zip > realtek.c, change:2009-11-22,size:16895b


/* 
 * Copyright (C) 2001-2006 by egnite Software GmbH 
 * Copyright (C) 2009 by egnite GmbH 
 * 
 * All rights reserved. 
 * 
 * Redistribution and use in source and binary forms, with or without 
 * modification, are permitted provided that the following conditions 
 * are met: 
 * 
 * 1. Redistributions of source code must retain the above copyright 
 *    notice, this list of conditions and the following disclaimer. 
 * 2. Redistributions in binary form must reproduce the above copyright 
 *    notice, this list of conditions and the following disclaimer in the 
 *    documentation and/or other materials provided with the distribution. 
 * 3. Neither the name of the copyright holders nor the names of 
 *    contributors may be used to endorse or promote products derived 
 *    from this software without specific prior written permission. 
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 
 * SUCH DAMAGE. 
 * 
 * For additional information see http://www.ethernut.de/ 
 */ 
 
/* 
 * $Id: realtek.c 2697 2009-09-14 16:39:14Z haraldkipp $ 
 * 
 * WARNING! Do not use any part of Basemon for your own applications. WARNING! 
 * 
 * This is not a typical application sample. It overrides parts of Nut/OS to 
 * keep it running on broken hardware. 
 */ 
 
#include <avr/io.h>
#include <avr/pgmspace.h> 
#include <avr/interrupt.h> 
#include <stdio.h> 
//#include <sys/timer.h> 
 
#include "basemon.h" 
#include "utils.h" 
#include "uart.h" 
#include "rtlregs.h" 
#include "realtek.h" 
#include "delay.h" 
#include "EtherBaz_Define.h" 
 
 
 
#define RTL_EESK_BIT    5 
#define RTL_EESK_PORT   PORTC 
#define RTL_EESK_PIN    PINC 
#define RTL_EESK_DDR    DDRC 
 
#define RTL_EEDO_BIT    6 
#define RTL_EEDO_PORT   PORTC 
#define RTL_EEDO_DDR    DDRC 
 
#define RTL_EEMU_BIT    7 
#define RTL_EEMU_PORT   PORTC 
#define RTL_EEMU_DDR    DDRC 
 
#define RTL_EE_MEMBUS 
 
static uint8_t *nic_base; 
char buf_txt[32];	//bufor dlaskladania tekstow itp dla LCD 
 
 
static int NicReset(void) 
{ 
    volatile uint8_t *base = nic_base; 
    uint8_t i; 
    uint8_t j; 
 
    /* Start command clears the reset bit. */ 
    nic_write(NIC_CR, NIC_CR_STA | NIC_CR_RD2); 
    //printf("[%02X]", nic_read(NIC_PG0_ISR)); 
    for (j = 0; j < 20; j++) { 
        printf("SW-Reset..."); 
        i = nic_read(NIC_RESET); 
        delay_ms(500); 
        nic_write(NIC_RESET, i); 
        for (i = 0; i < 20; i++) { 
            //delay_ms(5000); 
            /* 
             * ID detection added for version 1.1 boards. 
             */ 
            if ((nic_read(NIC_PG0_ISR) & NIC_ISR_RST) != 0 && nic_read(NIC_PG0_RBCR0) == 0x50 && nic_read(NIC_PG0_RBCR1) == 0x70) { 
                printf("OK"); 
                return 0; 
            } 
        } 
        printf("failed\x07"); 
        /* 
         * Toggle the hardware reset line. Since Ethernut version 1.3 the 
         * hardware reset pin of the nic is no longer connected to bit 4 
         * on port E, but wired to the board reset line. 
         */ 
        if (j == 10) { 
            printf("HW-Reset"); 
#if defined (__AVR__) 
            sbi(DDRE, 4); 
            sbi(PORTE, 4); 
            delay_ms(1000); 
            cbi(PORTE, 4); 
            delay_ms(2500); 
#endif 
        } 
    } 
    return -1; 
} 
 
static int DetectNicEeprom(void) 
{ 
#ifdef __AVR_ENHANCED__ 
    register unsigned int cnt = 0; 
 
    cli(); 
    /* 
     * Prepare the EEPROM emulation port bits. Configure the EEDO 
     * and the EEMU lines as outputs and set both lines to high. 
     */ 
    outb(PORTC, 0xC0); 
    outb(DDRC, 0xC0); 
 
    /* 
     * Force the chip to re-read the EEPROM contents. 
     */ 
    nic_outlb(NIC_CR, NIC_CR_STP | NIC_CR_RD2 | NIC_CR_PS0 | NIC_CR_PS1); 
    nic_outlb(NIC_PG3_EECR, NIC_EECR_EEM0); 
 
    /* 
     * No external memory access beyond this point. 
     */ 
#if defined(__AVR_AT90CAN128__) || defined(__AVR_ATmega2561__) 
    cbi(XMCRA, SRE); 
#else 
    cbi(MCUCR, SRE); 
#endif 
 
    /* 
     * Check, if the chip toggles our EESK input. If not, we do not 
     * have EEPROM emulation hardware. 
     */ 
    if(bit_is_set(PINC, 5)) { 
        while(++cnt && bit_is_set(PINC, 5)); 
    } 
    else { 
        while(++cnt && bit_is_clear(PINC, 5)); 
    } 
 
    /* 
     * Enable memory interface. 
     */ 
#if defined(__AVR_AT90CAN128__) || defined(__AVR_ATmega2561__) 
    sbi(XMCRA, SRE); 
#else 
    sbi(MCUCR, SRE); 
#endif 
 
    /* Reset port outputs to default. */ 
    outb(PORTC, 0x00); 
    outb(DDRC, 0x00); 
 
    /* Wait until controller ready. */ 
    while(nic_inlb(NIC_CR) != (NIC_CR_STP | NIC_CR_RD2)); 
 
    sei(); 
    return cnt ? 0 : -1; 
#else 
    return -1; 
#endif 
} 
 
/* 
 * Emulated EEPROM contents. 
 * 
 * In jumper mode our influence is quite limited, only CONFIG3 and CONFIG4 
 * can be modified. 
 */ 
static prog_char nic_eeprom[18] = { 
    0xFF,   /* CONFIG2: jPL1 jPL0   0      jBS4   jBS3   jBS2  jBS1  jBS0  */ 
    0xFF,   /* CONFIG1: 1    jIRQS2 jIRQS1 jIRQS0 jIOS3  jIOS2 jIOS1 jIOS0 */ 
 
    0xFF,   /* CONFIG4: -    -      -      -      -      -     -     IOMS  */ 
    0x30,   /* CONFIG3  PNP  FUDUP  LEDS1  LEDS0  -      0     PWRDN ACTB  */ 
 
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* MAC */ 
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF /* ID */ 
}; 
 
/*! 
 * \brief EEPROM emulator. 
 * 
 * Forces the chip to re-read the EEPROM contents and emulates a serial 
 * EEPROM. 
 * 
 * If the hardware does not support this feature, then this call will 
 * never return. Thus, make sure to have the driver properly configured. 
 */ 
static void EmulateNicEeprom(void) 
{ 
#ifdef __AVR_ENHANCED__ 
    register uint8_t clk; 
    register uint8_t cnt; 
    register uint8_t val; 
 
    /* 
     * Prepare the EEPROM emulation port bits. Configure the EEDO and 
     * the EEMU lines as outputs and set EEDO to low and EEMU to high. 
     */ 
    outb(PORTC, 0xC0); 
    outb(DDRC, 0xC0); 
 
    /* 
     * Start EEPROM configuration. Stop/abort any activity and select 
     * configuration page 3. Setting bit EEM0 will force the controller 
     * to read the EEPROM contents. 
     */ 
 
    /* Select page 3, stop and abort/complete. */ 
    nic_outlb(NIC_CR, NIC_CR_STP | NIC_CR_RD2 | NIC_CR_PS0 | NIC_CR_PS1); 
    nic_outlb(NIC_PG3_EECR, NIC_EECR_EEM0); 
 
    /* 
     * We can avoid wasting port pins for EEPROM emulation by using the 
     * upper bits of the address bus. 
     */ 
    /* 
     * No external memory access beyond this point. 
     */ 
#if defined(__AVR_AT90CAN128__) || defined(__AVR_ATmega2561__) 
    cbi(XMCRA, SRE); 
#else 
    cbi(MCUCR, SRE); 
#endif 
 
    /* 
     * Loop for all EEPROM words. 
     */ 
    for(cnt = 0; cnt < sizeof(nic_eeprom); ) { 
 
        /* 
         * 
         * 1 start bit, always high 
         * 2 op-code bits 
         * 7 address bits 
         * 1 dir change bit, always low 
         */ 
        for(clk = 0; clk < 11; clk++) { 
            while(bit_is_clear(RTL_EESK_PIN, RTL_EESK_BIT)); 
            while(bit_is_set(RTL_EESK_PIN, RTL_EESK_BIT)); 
        } 
 
        /* 
         * Shift out the high byte, MSB first. Our data changes at the EESK 
         * rising edge. Data is sampled by the Realtek at the falling edge. 
         */ 
        val = PRG_RDB(nic_eeprom + cnt); 
        cnt++; 
        for(clk = 0x80; clk; clk >>= 1) { 
            while(bit_is_clear(RTL_EESK_PIN, RTL_EESK_BIT)); 
            if(val & clk) 
                sbi(RTL_EEDO_PORT, RTL_EEDO_BIT); 
            while(bit_is_set(RTL_EESK_PIN, RTL_EESK_BIT)); 
            cbi(RTL_EEDO_PORT, RTL_EEDO_BIT); 
        } 
 
        /* 
         * Shift out the low byte. 
         */ 
        val = PRG_RDB(nic_eeprom + cnt); 
        cnt++; 
        for(clk = 0x80; clk; clk >>= 1) { 
            while(bit_is_clear(RTL_EESK_PIN, RTL_EESK_BIT)); 
            if(val & clk) 
                sbi(RTL_EEDO_PORT, RTL_EEDO_BIT); 
            while(bit_is_set(RTL_EESK_PIN, RTL_EESK_BIT)); 
            cbi(RTL_EEDO_PORT, RTL_EEDO_BIT); 
        } 
 
 
        /* 5 remaining clock cycles. */ 
        for(clk = 0; clk < 5; clk++) { 
            while(bit_is_clear(RTL_EESK_PIN, RTL_EESK_BIT)); 
            while(bit_is_set(RTL_EESK_PIN, RTL_EESK_BIT)); 
        } 
    } 
 
    /* 
     * Enable memory interface. 
     */ 
#if defined(__AVR_AT90CAN128__) || defined(__AVR_ATmega2561__) 
    sbi(XMCRA, SRE); 
#else 
    sbi(MCUCR, SRE); 
#endif 
 
    /* Reset port outputs to default. */ 
    outb(PORTC, 0x00); 
    outb(DDRC, 0x00); 
#endif 
} 
 
static int RealtekProbe(size_t addr) 
{ 
    uint8_t bv; 
 
    nic_base = (uint8_t *)addr; 
    bv = nic_inlb(NIC_CR); 
    if(bv & (NIC_CR_PS0 | NIC_CR_PS1)) { 
        nic_outlb(NIC_CR, NIC_CR_STP | NIC_CR_RD2); 
    } 
    if(nic_inw(NIC_PG0_RBCR0) != 0x7050) { 
        return -1; 
    } 
    return 0; 
} 
 
/*! 
 * \brief Detect an RTL8019AS chip. 
 */ 
int RealtekDetect(void) 
{ 
    size_t addr; 
 
    if (RealtekProbe(NIC_BASE) == 0) { 
        return 0; 
    } 
    for (addr = 0x8000; addr; addr += 0x100) { 
        if (RealtekProbe(addr) == 0) { 
            return 0; 
        } 
    } 
    return -1; 
} 
 
void RealtekLoop(void) 
{ 
   // printf_P(presskey_P); 
    for (;;) { 
        nic_outlb(NIC_CR, NIC_CR_STP | NIC_CR_RD2); 
		sprintf (buf_txt,"\rid=0x%04X", nic_inw(NIC_PG0_RBCR0)); 
        printf(buf_txt); 
 //       if (GetChar()) { 
 //           puts(""); 
 //           return; 
  //      } 
  		delay_ms(1000); 
    } 
} 
 
int RealtekTest(void) 
{ 
    int i; 
    uint8_t force_swreset = 0; 
    volatile uint8_t *base = nic_base; 
    uint16_t nic_id; 
 
    /* 
     * NIC ID detection loop. 
     */ 
    for (;;) { 
        /* 
         * Reset loop. 
         */ 
        for (;;) { 
 
            /* 
             * The hardware reset pin of the nic is connected 
             * to bit 4 on port E. Make this pin an output pin 
             * and toggle it. 
             */ 
#if defined(__AVR__) 
            sbi(DDRE, 4); 
            sbi(PORTE, 4); 
            delay_ms(200); 
            cbi(PORTE, 4); 
            delay_ms(200); 
#endif 
            /* 
             * If the hardware reset didn't set the nic in reset 
             * state, perform an additional software reset and 
             * wait until the controller enters the reset state. 
             */ 
            if (force_swreset || (*(base + 7) & 0x80) == 0) { 
                *(base + 0x1f) = *(base + 0x1f); 
                delay_ms(2000); 
                for (i = 0; i < 255; i++) { 
                    if (*(base + 7) & 0x80) { 
                        break; 
                    } 
                } 
                if (i < 255) { 
                    break; 
                } 
                printf("failed"); 
            } else { 
                break; 
            } 
//            if (uart_bs >= 0) 
//                break; 
        } 
        nic_id = nic_inw(NIC_PG0_RBCR0); 
        if (nic_id == 0x7050) { 
            printf("OK"); 
            break; 
        } 
		sprintf (buf_txt,"BLAD, jest 0x%04X", nic_id); 
		printf(buf_txt); 
		printf("zamiast 0x7050"); 
        if (force_swreset >= 0) 
            break; 
        force_swreset = 1; 
    } 
    return 0; 
} 
 
#define NIC_PAGE_SIZE       0x100 
#define NIC_START_PAGE      0x40 
#define NIC_STOP_PAGE       0x60 
#define NIC_TX_PAGES        6 
#define NIC_TX_BUFFERS      2 
#define NIC_FIRST_TX_PAGE   NIC_START_PAGE 
#define NIC_FIRST_RX_PAGE   (NIC_FIRST_TX_PAGE + NIC_TX_PAGES * NIC_TX_BUFFERS) 
#define TX_PAGES            12 
 
void RealtekSend(void) 
{ 
    uint8_t mac[] = { 
        0x00, 0x06, 0x98, 0x00, 0x00, 0x00 
    }; 
    uint16_t sz; 
    uint16_t i; 
    volatile uint8_t *base = nic_base; 
    uint8_t rb; 
    uint32_t cnt = 0; 
 
    printf("Init controller..."); 
//    printf("Init controller..."); 
    nic_write(NIC_PG0_IMR, 0); 
    nic_write(NIC_PG0_ISR, 0xff); 
    if (NicReset()) 
        return; 
	 
	printf(" detecting..."); 
   // printf(" detecting..."); 
    delay_ms(50); 
    if (DetectNicEeprom() == 0) { 
        printf("EEPROM Emulation..."); 
        EmulateNicEeprom(); 
    } 
 
    nic_write(NIC_CR, NIC_CR_STP | NIC_CR_RD2 | NIC_CR_PS0 | NIC_CR_PS1); 
    nic_write(NIC_PG3_EECR, NIC_EECR_EEM0 | NIC_EECR_EEM1); 
    nic_write(NIC_PG3_CONFIG3, 0); 
    nic_write(NIC_PG3_CONFIG2, NIC_CONFIG2_BSELB); 
    nic_write(NIC_PG3_EECR, 0); 
 
    delay_ms(30); 
    nic_write(NIC_CR, NIC_CR_STP | NIC_CR_RD2); 
    nic_write(NIC_PG0_DCR, NIC_DCR_LS | NIC_DCR_FT1); 
    nic_write(NIC_PG0_RBCR0, 0); 
    nic_write(NIC_PG0_RBCR1, 0); 
    nic_write(NIC_PG0_RCR, NIC_RCR_MON); 
    nic_write(NIC_PG0_TCR, NIC_TCR_LB0); 
    nic_write(NIC_PG0_TPSR, NIC_FIRST_TX_PAGE); 
    nic_write(NIC_PG0_BNRY, NIC_STOP_PAGE - 1); 
    nic_write(NIC_PG0_PSTART, NIC_FIRST_RX_PAGE); 
    nic_write(NIC_PG0_PSTOP, NIC_STOP_PAGE); 
    nic_write(NIC_PG0_ISR, 0xff); 
    nic_write(NIC_CR, NIC_CR_STP | NIC_CR_RD2 | NIC_CR_PS0); 
    for (i = 0; i < 6; i++) 
        nic_write(NIC_PG1_PAR0 + i, mac[i]); 
    for (i = 0; i < 8; i++) 
        nic_write(NIC_PG1_MAR0 + i, 0); 
    nic_write(NIC_PG1_CURR, NIC_START_PAGE + TX_PAGES); 
    nic_write(NIC_CR, NIC_CR_STP | NIC_CR_RD2); 
    nic_write(NIC_PG0_RCR, NIC_RCR_AB); 
    nic_write(NIC_PG0_ISR, 0xff); 
    nic_write(NIC_PG0_IMR, 0); 
    nic_write(NIC_CR, NIC_CR_STA | NIC_CR_RD2); 
    nic_write(NIC_PG0_TCR, 0); 
    delay_ms(30); 
	printf(" done"); 
    //puts("done"); 
    nic_write(NIC_CR, NIC_CR_STA | NIC_CR_RD2 | NIC_CR_PS0 | NIC_CR_PS1); 
    rb = nic_read(NIC_PG3_CONFIG0); 
    switch (rb & 0xC0) { 
    case 0x00: 
        printf("RTL8019AS "); 
        if (rb & 0x08) 
            printf("jumper mode: "); 
        if (rb & 0x20) 
            printf("AUI "); 
        if (rb & 0x10) 
            printf("PNP "); 
        break; 
    case 0xC0: 
        printf("RTL8019 "); 
        if (rb & 0x08) 
            printf("jumper mode: "); 
        break; 
    default: 
        printf("Unknown chip "); 
        break; 
    } 
    if (rb & 0x04) 
        printf("BNC\x07 "); 
    if (rb & 0x03) 
        printf("Failed\x07 "); 
    rb = nic_read(NIC_PG3_CONFIG1); 
    printf("IRQ%u ", (rb >> 4) & 7); 
    rb = nic_read(NIC_PG3_CONFIG2); 
    switch (rb & 0xC0) { 
    case 0x00: 
        printf("Auto "); 
        break; 
    case 0x40: 
        printf("10BaseT "); 
        break; 
    case 0x80: 
        printf("10Base5 "); 
        break; 
    case 0xC0: 
        printf("10Base2 "); 
        break; 
    } 
 
 
    printf("\n"); 
    nic_write(NIC_CR, NIC_CR_STA | NIC_CR_RD2); 
    for (;;) { 
        delay_ms(30); 
        printf("\r%lu", cnt++); 
        sz = 1500; 
        nic_write(NIC_PG0_RBCR0, sz); 
        nic_write(NIC_PG0_RBCR1, sz >> 8); 
        nic_write(NIC_PG0_RSAR0, 0); 
        nic_write(NIC_PG0_RSAR1, NIC_FIRST_TX_PAGE); 
        nic_write(NIC_CR, NIC_CR_STA | NIC_CR_RD1); 
        /* 
         * Transfer ethernet physical header. 
         */ 
        for (i = 0; i < 6; i++) 
            nic_write(NIC_IOPORT, 0xFF); 
        for (i = 0; i < 6; i++) 
            nic_write(NIC_IOPORT, mac[i]); 
        nic_write(NIC_IOPORT, 0x08); 
        nic_write(NIC_IOPORT, 0x00); 
        /* 
         * Add pad bytes. 
         */ 
        for (i = 0; i < sz; i++) 
            nic_write(NIC_IOPORT, 0); 
        /* 
         * Complete remote dma. 
         */ 
        nic_write(NIC_CR, NIC_CR_STA | NIC_CR_RD2); 
        for (i = 0; i <= 20; i++) 
            if (nic_read(NIC_PG0_ISR) & NIC_ISR_RDC) 
                break; 
        nic_write(NIC_PG0_ISR, NIC_ISR_RDC); 
        /* 
         * Number of bytes to be transmitted. 
         */ 
        nic_write(NIC_PG0_TBCR0, (sz & 0xff)); 
        nic_write(NIC_PG0_TBCR1, ((sz >> 8) & 0xff)); 
        /* 
         * First page of packet to be transmitted. 
         */ 
        nic_write(NIC_PG0_TPSR, NIC_FIRST_TX_PAGE); 
        /* 
         * Start transmission. 
         */ 
        nic_write(NIC_CR, NIC_CR_STA | NIC_CR_TXP | NIC_CR_RD2); 
//        if (GetChar()) 
//            break; 
        delay_ms(50); 
    } 
}