| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578 |
- /*
- * 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 3597 2011-10-21 16:17:18Z 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 <stdio.h>
- #include <sys/timer.h>
- #include "basemon.h"
- #include "utils.h"
- #include "uart.h"
- #include "rtlregs.h"
- #include "realtek.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;
- 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(500);
- nic_write(NIC_RESET, i);
- for (i = 0; i < 20; i++) {
- //Delay(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) {
- puts("OK");
- return 0;
- }
- }
- puts("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) {
- puts("HW-Reset");
- #if defined (__AVR__)
- sbi(DDRE, 4);
- sbi(PORTE, 4);
- Delay(100000);
- cbi(PORTE, 4);
- Delay(250000);
- #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);
- printf("\rid=0x%04X", nic_inw(NIC_PG0_RBCR0));
- if (GetChar()) {
- puts("");
- return;
- }
- }
- }
- 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(2000);
- cbi(PORTE, 4);
- Delay(20000);
- #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(200000);
- for (i = 0; i < 255; i++) {
- if (*(base + 7) & 0x80) {
- break;
- }
- }
- if (i < 255) {
- break;
- }
- puts("failed\x07");
- } else {
- break;
- }
- if (uart_bs >= 0)
- break;
- }
- nic_id = nic_inw(NIC_PG0_RBCR0);
- if (nic_id == 0x7050) {
- puts("OK");
- break;
- }
- printf("failed, got 0x%04X, expected 0x7050\n\x07", nic_id);
- if (force_swreset && uart_bs >= 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...");
- nic_write(NIC_PG0_IMR, 0);
- nic_write(NIC_PG0_ISR, 0xff);
- if (NicReset())
- return;
- printf(" detecting...");
- Delay(200000);
- 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(50000);
- 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(1000000);
- 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(500000);
- 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(10000);
- }
- }
|