From 771c1479beac0bd906de14d015ecad4b4149cdb6 Mon Sep 17 00:00:00 2001 From: Joel Sherrill Date: Sat, 3 Jul 1999 15:38:38 +0000 Subject: New files missed in previous addition. --- c/src/lib/libbsp/powerpc/mcp750/bootloader/README | 41 + .../lib/libbsp/powerpc/mcp750/dec21140/dec21140.c | 907 +++++++++++++++++++++ .../powerpc/motorola_powerpc/bootloader/README | 41 + .../powerpc/motorola_powerpc/dec21140/dec21140.c | 907 +++++++++++++++++++++ 4 files changed, 1896 insertions(+) create mode 100644 c/src/lib/libbsp/powerpc/mcp750/bootloader/README create mode 100644 c/src/lib/libbsp/powerpc/mcp750/dec21140/dec21140.c create mode 100644 c/src/lib/libbsp/powerpc/motorola_powerpc/bootloader/README create mode 100644 c/src/lib/libbsp/powerpc/motorola_powerpc/dec21140/dec21140.c diff --git a/c/src/lib/libbsp/powerpc/mcp750/bootloader/README b/c/src/lib/libbsp/powerpc/mcp750/bootloader/README new file mode 100644 index 0000000000..6d36a152ba --- /dev/null +++ b/c/src/lib/libbsp/powerpc/mcp750/bootloader/README @@ -0,0 +1,41 @@ +# +# $Id$ +# + +The code in this directory has been taken WITH PERMISSION from +Gabriel Paubert, paubert@iram.es. The main reason for having +a separate bootloader for PreP compliant firmware is that the +initial code is relocated by firmware at an unknow address +(actually 0x5000 on motorola MCP750) and that as Gabriel I +think having a relocatable bootloder code is a must. + +So the way of building a binary executable that can be booted via +hard disk or network boot goes like this : + + - make a RTEMS executable, + - put is as data section in the bootloder binary, + - relink the loader (see make-exe macros for details), + +I would like to thank Gabriel for his support and his code. +The original code can be found in form of a patch to official linux +kernel at (I insist not vger ppc kernel or Imac ppc kernels!!) : + + + +After applying the patch, the code is located in a new directory +called prepboot. + +(NB : note use ftp not netscape...) + +Note that the actual code differs a lot since Gabriel choose to use +a CHRP compliant mapping instead of a Prep Mapping to save +BATs. I had no time to upgrade the code to its new one allthough +I agree it should be done... + +I have also splitted the original code to have a more modular +design enabling to reuse code between the loader and RTEMS +initialization (e.g printk, ...). + +Eric Valette (valette@crf.canon.fr) + + diff --git a/c/src/lib/libbsp/powerpc/mcp750/dec21140/dec21140.c b/c/src/lib/libbsp/powerpc/mcp750/dec21140/dec21140.c new file mode 100644 index 0000000000..b5a602645d --- /dev/null +++ b/c/src/lib/libbsp/powerpc/mcp750/dec21140/dec21140.c @@ -0,0 +1,907 @@ +/* + * RTEMS driver for TULIP based Ethernet Controller + * + * Copyright (C) 1999 Emmanuel Raguet. raguet@crf.canon.fr + * + * The license and distribution terms for this file may be + * found in found in the file LICENSE in this distribution or at + * http://www.OARcorp.com/rtems/license.html. + * + * $Id$ + */ + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include + +#ifdef malloc +#undef malloc +#endif +#ifdef free +#undef free +#endif + +#define DEC_DEBUG + +#define PCI_INVALID_VENDORDEVICEID 0xffffffff +#define PCI_VENDOR_ID_DEC 0x1011 +#define PCI_DEVICE_ID_DEC_TULIP_FAST 0x0009 + +#define IO_MASK 0x3 +#define MEM_MASK 0xF +#define MASK_OFFSET 0xF + +/* command and status registers, 32-bit access, only if IO-ACCESS */ +#define ioCSR0 0x00 /* bus mode register */ +#define ioCSR1 0x08 /* transmit poll demand */ +#define ioCSR2 0x10 /* receive poll demand */ +#define ioCSR3 0x18 /* receive list base address */ +#define ioCSR4 0x20 /* transmit list base address */ +#define ioCSR5 0x28 /* status register */ +#define ioCSR6 0x30 /* operation mode register */ +#define ioCSR7 0x38 /* interrupt mask register */ +#define ioCSR8 0x40 /* missed frame counter */ +#define ioCSR9 0x48 /* Ethernet ROM register */ +#define ioCSR10 0x50 /* reserved */ +#define ioCSR11 0x58 /* full-duplex register */ +#define ioCSR12 0x60 /* SIA status register */ +#define ioCSR13 0x68 +#define ioCSR14 0x70 +#define ioCSR15 0x78 /* SIA general register */ + +/* command and status registers, 32-bit access, only if MEMORY-ACCESS */ +#define memCSR0 0x00 /* bus mode register */ +#define memCSR1 0x02 /* transmit poll demand */ +#define memCSR2 0x04 /* receive poll demand */ +#define memCSR3 0x06 /* receive list base address */ +#define memCSR4 0x08 /* transmit list base address */ +#define memCSR5 0x0A /* status register */ +#define memCSR6 0x0C /* operation mode register */ +#define memCSR7 0x0E /* interrupt mask register */ +#define memCSR8 0x10 /* missed frame counter */ +#define memCSR9 0x12 /* Ethernet ROM register */ +#define memCSR10 0x14 /* reserved */ +#define memCSR11 0x16 /* full-duplex register */ +#define memCSR12 0x18 /* SIA status register */ +#define memCSR13 0x1A +#define memCSR14 0x1C +#define memCSR15 0x1E /* SIA general register */ + +#define DEC_REGISTER_SIZE 0x100 /* to reserve virtual memory */ + +#define RESET_CHIP 0x00000001 +#define CSR0_MODE 0x01b08000 /* 01a08000 */ +#define ROM_ADDRESS 0x00004800 +#define CSR6_INIT 0x020c0000 /* 020c0000 */ +#define CSR6_TX 0x00002000 +#define CSR6_TXRX 0x00002002 +#define IT_SETUP 0x00010040 /* 0001ebef */ +#define CLEAR_IT 0xFFFFFFFF +#define NO_IT 0x00000000 + +#define NRXBUFS 7 /* number of receive buffers */ +#define NTXBUFS 1 /* number of transmit buffers */ + +/* message descriptor entry */ +struct MD { + volatile unsigned long status; + volatile unsigned long counts; + unsigned long buf1, buf2; +}; + +/* + * Number of WDs supported by this driver + */ +#define NDECDRIVER 1 + +/* + * Receive buffer size -- Allow for a full ethernet packet including CRC + */ +#define RBUF_SIZE 1520 + +#define ET_MINLEN 60 /* minimum message length */ + +/* + * RTEMS event used by interrupt handler to signal driver tasks. + * This must not be any of the events used by the network task synchronization. + */ +#define INTERRUPT_EVENT RTEMS_EVENT_1 + +/* + * RTEMS event used to start transmit daemon. + * This must not be the same as INTERRUPT_EVENT. + */ +#define START_TRANSMIT_EVENT RTEMS_EVENT_2 + +#if (MCLBYTES < RBUF_SIZE) +# error "Driver must have MCLBYTES > RBUF_SIZE" +#endif + +/* + * Per-device data + */ + struct dec21140_softc { + struct arpcom arpcom; + rtems_irq_connect_data irqInfo; + struct MD *MDbase; + char *bufferBase; + int acceptBroadcast; + int rxBdCount; + int txBdCount; + rtems_id rxDaemonTid; + rtems_id txDaemonTid; + + unsigned int port; + unsigned int *base; + unsigned long bpar; + + /* + * Statistics + */ + unsigned long rxInterrupts; + unsigned long rxNotFirst; + unsigned long rxNotLast; + unsigned long rxGiant; + unsigned long rxNonOctet; + unsigned long rxRunt; + unsigned long rxBadCRC; + unsigned long rxOverrun; + unsigned long rxCollision; + + unsigned long txInterrupts; + unsigned long txDeferred; + unsigned long txHeartbeat; + unsigned long txLateCollision; + unsigned long txRetryLimit; + unsigned long txUnderrun; + unsigned long txLostCarrier; + unsigned long txRawWait; +}; + +static struct dec21140_softc dec21140_softc[NDECDRIVER]; + +/* + * DEC21140 interrupt handler + */ +static rtems_isr +dec21140Enet_interrupt_handler (rtems_vector_number v) +{ + unsigned int *tbase; + unsigned long status; + + unsigned int sc; + + tbase = dec21140_softc[0].base ; + + /* + * Read status + */ + st_le32((tbase+memCSR7), NO_IT); + status = ld_le32(tbase+memCSR5); + st_le32((tbase+memCSR5), CLEAR_IT); + + /* + * Frame received? + */ + if (status & 0x00000040){ + dec21140_softc[0].rxInterrupts++; + sc = rtems_event_send (dec21140_softc[0].rxDaemonTid, INTERRUPT_EVENT); + } +} + +static void nopOn(const rtems_irq_connect_data* notUsed) +{ + /* + * code should be moved from dec21140Enet_initialize_hardware + * to this location + */ +} + +static int dec21140IsOn(const rtems_irq_connect_data* irq) +{ + return BSP_irq_enabled_at_i8259s (irq->name); +} + +/* + * Read and write the MII registers using software-generated serial + * MDIO protocol. + */ +#define MDIO_SHIFT_CLK 0x10000 +#define MDIO_DATA_WRITE0 0x00000 +#define MDIO_DATA_WRITE1 0x20000 +#define MDIO_ENB 0x00000 +#define MDIO_ENB_IN 0x40000 +#define MDIO_DATA_READ 0x80000 + +static int mdio_read(unsigned int *ioaddr, int phy_id, int location) +{ + int i, i3; + int read_cmd = (0xf6 << 10) | (phy_id << 5) | location; + unsigned short retval = 0; + + /* Establish sync by sending at least 32 logic ones. */ + for (i = 32; i >= 0; i--) { + st_le32(ioaddr, MDIO_ENB | MDIO_DATA_WRITE1); + for(i3=0; i3<1000; i3++); + st_le32(ioaddr, MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK); + for(i3=0; i3<1000; i3++); + } + /* Shift the read command bits out. */ + for (i = 17; i >= 0; i--) { + int dataval = (read_cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0; + st_le32(ioaddr, dataval); + for(i3=0; i3<1000; i3++); + st_le32(ioaddr, dataval | MDIO_SHIFT_CLK); + for(i3=0; i3<1000; i3++); + st_le32(ioaddr, dataval); + for(i3=0; i3<1000; i3++); + } + st_le32(ioaddr, MDIO_ENB_IN | MDIO_SHIFT_CLK); + for(i3=0; i3<1000; i3++); + st_le32(ioaddr, MDIO_ENB_IN); + + for (i = 16; i > 0; i--) { + st_le32(ioaddr, MDIO_ENB_IN | MDIO_SHIFT_CLK); + for(i3=0; i3<1000; i3++); + retval = (retval << 1) | ((ld_le32(ioaddr) & MDIO_DATA_READ) ? 1 : 0); + st_le32(ioaddr, MDIO_ENB_IN); + for(i3=0; i3<1000; i3++); + } + /* Clear out extra bits. */ + for (i = 16; i > 0; i--) { + st_le32(ioaddr, MDIO_ENB_IN | MDIO_SHIFT_CLK); + for(i3=0; i3<1000; i3++); + st_le32(ioaddr, MDIO_ENB_IN); + for(i3=0; i3<1000; i3++); + } + return ( ((retval<<8)&0xff00) | ((retval>>8)&0xff) ); +} + +static int mdio_write(unsigned int *ioaddr, int phy_id, int location, int value) +{ + int i, i3; + int cmd = (0x5002 << 16) | (phy_id << 23) | (location << 18) | value; + + /* Establish sync by sending at least 32 logic ones. */ + for (i = 32; i >= 0; i--) { + st_le32(ioaddr, MDIO_ENB | MDIO_DATA_WRITE1); + for(i3=0; i3<1000; i3++); + st_le32(ioaddr, MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK); + for(i3=0; i3<1000; i3++); + } + /* Shift the read command bits out. */ + for (i = 31; i >= 0; i--) { + int dataval = (cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0; + st_le32(ioaddr, dataval); + for(i3=0; i3<1000; i3++); + st_le32(ioaddr, dataval | MDIO_SHIFT_CLK); + for(i3=0; i3<1000; i3++); + } + + /* Clear out extra bits. */ + for (i = 2; i > 0; i--) { + st_le32(ioaddr, MDIO_ENB_IN); + for(i3=0; i3<1000; i3++); + st_le32(ioaddr, MDIO_ENB_IN | MDIO_SHIFT_CLK); + for(i3=0; i3<1000; i3++); + } + return 0; + + +} + +/* + * This routine reads a word (16 bits) from the serial EEPROM. + */ +/* EEPROM_Ctrl bits. */ +#define EE_SHIFT_CLK 0x02 /* EEPROM shift clock. */ +#define EE_CS 0x01 /* EEPROM chip select. */ +#define EE_DATA_WRITE 0x04 /* EEPROM chip data in. */ +#define EE_WRITE_0 0x01 +#define EE_WRITE_1 0x05 +#define EE_DATA_READ 0x08 /* EEPROM chip data out. */ +#define EE_ENB (0x4800 | EE_CS) + +/* The EEPROM commands include the alway-set leading bit. */ +#define EE_WRITE_CMD (5 << 6) +#define EE_READ_CMD (6 << 6) +#define EE_ERASE_CMD (7 << 6) + +static int eeget16(unsigned int *ioaddr, int location) +{ + int i, i3; + unsigned short retval = 0; + int read_cmd = location | EE_READ_CMD; + + st_le32(ioaddr, EE_ENB & ~EE_CS); + st_le32(ioaddr, EE_ENB); + + /* Shift the read command bits out. */ + for (i = 10; i >= 0; i--) { + short dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0; + st_le32(ioaddr, EE_ENB | dataval); + for (i3=0; i3<1000; i3++) ; + st_le32(ioaddr, EE_ENB | dataval | EE_SHIFT_CLK); + for (i3=0; i3<1000; i3++) ; + st_le32(ioaddr, EE_ENB | dataval); /* Finish EEPROM a clock tick. */ + for (i3=0; i3<1000; i3++) ; + } + st_le32(*ioaddr, EE_ENB); + + for (i = 16; i > 0; i--) { + st_le32(ioaddr, EE_ENB | EE_SHIFT_CLK); + for (i3=0; i3<1000; i3++) ; + retval = (retval << 1) | ((ld_le32(ioaddr) & EE_DATA_READ) ? 1 : 0); + st_le32(ioaddr, EE_ENB); + for (i3=0; i3<1000; i3++) ; + } + + /* Terminate the EEPROM access. */ + st_le32(*ioaddr, EE_ENB & ~EE_CS); + return ( ((retval<<8)&0xff00) | ((retval>>8)&0xff) ); +} + +/* + * Initialize the ethernet hardware + */ +static void +dec21140Enet_initialize_hardware (struct dec21140_softc *sc) +{ + rtems_status_code st; + unsigned int *tbase; + union {char c[64]; unsigned short s[32];} rombuf; + int i, i2, i3; + char *cp, direction, *setup_frm, *eaddrs; + unsigned long csr12_val, mii_reg0; + unsigned char *buffer; + struct MD *rmd; + + + tbase = sc->base; + + + + /* + * WARNING : First write in CSR6 + * Then Reset the chip ( 1 in CSR0) + */ + + st_le32( (tbase+memCSR6), CSR6_INIT); + st_le32( (tbase+memCSR0), RESET_CHIP); + for(i3=0; i3<1000; i3++); + + /* + * Init CSR0 + */ + st_le32( (tbase+memCSR0), CSR0_MODE); + + csr12_val = ld_le32( (tbase+memCSR8) ); + + for (i=0; i<32; i++){ + rombuf.s[i] = eeget16(tbase+memCSR9, i); + } + memcpy (sc->arpcom.ac_enaddr, rombuf.c+20, ETHER_ADDR_LEN); + + mii_reg0 = mdio_read(tbase+memCSR9, 0, 0); + mdio_write(tbase+memCSR9, 0, 0, mii_reg0 | 0x1000); + +#ifdef DEC_DEBUG + printk("DC21140 %x:%x:%x:%x:%x:%x IRQ %d IO %x M %x .........\n", + sc->arpcom.ac_enaddr[0], sc->arpcom.ac_enaddr[1], + sc->arpcom.ac_enaddr[2], sc->arpcom.ac_enaddr[3], + sc->arpcom.ac_enaddr[4], sc->arpcom.ac_enaddr[5], + sc->irqInfo.name, sc->port, sc->base); +#endif + + /* + * Init RX ring + */ + sc->rxBdCount = 0; + cp = (char *)malloc((NRXBUFS+NTXBUFS)*(sizeof(struct MD)+ RBUF_SIZE) + PPC_CACHE_ALIGNMENT); + sc->bufferBase = cp; + cp += (PPC_CACHE_ALIGNMENT - (int)cp) & MASK_OFFSET; +#ifdef PCI_BRIDGE_DOES_NOT_ENSURE_CACHE_COHERENCY_FOR_DMA + if (_CPU_is_paging_enabled()) + _CPU_change_memory_mapping_attribute + (NULL, cp, + (NRXBUFS+NTXBUFS)*(sizeof(struct MD)+ RBUF_SIZE), + PTE_CACHE_DISABLE | PTE_WRITABLE); +#endif + rmd = (struct MD*)cp; + sc->MDbase = rmd; + buffer = cp + ((NRXBUFS+NTXBUFS)*sizeof(struct MD)); + st_le32( (tbase+memCSR3), (long)((long)(sc->MDbase) + PREP_PCI_DRAM_OFFSET)); + for (i=0 ; ibuf2 = 0; + rmd->buf1 = (unsigned long)(buffer + (i*RBUF_SIZE) + PREP_PCI_DRAM_OFFSET); + if (i == NRXBUFS-1) + rmd->counts = 0xfec00000 | (RBUF_SIZE); + else + rmd->counts = 0xfcc00000 | (RBUF_SIZE); + rmd->status = 0x80000000; + rmd++; + } + + /* + * Init TX ring + */ + sc->txBdCount = 0; + st_le32( (tbase+memCSR4), (long)((long)(rmd) + PREP_PCI_DRAM_OFFSET)); + rmd->buf2 = 0; + rmd->buf1 = (unsigned long)(buffer + (NRXBUFS*RBUF_SIZE) + PREP_PCI_DRAM_OFFSET); + rmd->counts = 0x62000000; + rmd->status = 0x0; + + /* + * Set up interrupts + */ + st_le32( (tbase+memCSR5), IT_SETUP); + st_le32( (tbase+memCSR7), IT_SETUP); + + sc->irqInfo.hdl = (rtems_irq_hdl)dec21140Enet_interrupt_handler; + sc->irqInfo.on = nopOn; + sc->irqInfo.off = nopOn; + sc->irqInfo.isOn = dec21140IsOn; + st = BSP_install_rtems_irq_handler (&sc->irqInfo); + if (!st) + rtems_panic ("Can't attach DEC21140 interrupt handler for irq %d\n", + sc->irqInfo.name); + + /* + * Start TX for setup frame + */ + st_le32( (tbase+memCSR6), CSR6_INIT | CSR6_TX); + + /* + * Build setup frame + */ + setup_frm = (char *)((long)(rmd->buf1) - PREP_PCI_DRAM_OFFSET); + eaddrs = (char *)(sc->arpcom.ac_enaddr); + /* Fill the buffer with our physical address. */ + for (i = 1; i < 16; i++) { + *setup_frm++ = eaddrs[0]; + *setup_frm++ = eaddrs[1]; + *setup_frm++ = eaddrs[0]; + *setup_frm++ = eaddrs[1]; + *setup_frm++ = eaddrs[2]; + *setup_frm++ = eaddrs[3]; + *setup_frm++ = eaddrs[2]; + *setup_frm++ = eaddrs[3]; + *setup_frm++ = eaddrs[4]; + *setup_frm++ = eaddrs[5]; + *setup_frm++ = eaddrs[4]; + *setup_frm++ = eaddrs[5]; + } + /* Add the broadcast address when doing perfect filtering */ + memset(setup_frm, 0xff, 12); + rmd->counts = 0x0a000000 | 192 ; + rmd->status = 0x80000000; + st_le32( (tbase+memCSR1), 1); + while (rmd->status != 0x7fffffff); + + /* + * Enable RX and TX + */ + st_le32( (unsigned int*)(tbase+memCSR6), CSR6_INIT | CSR6_TXRX); + + /* + * Set up PHY + */ + + i = rombuf.c[27]; + i+=2; + direction = rombuf.c[i]; + i +=4; + st_le32( (tbase+memCSR12), direction | 0x100); + for (i2 = 0; i2 < rombuf.c[(i+2) + rombuf.c[i+1]]; i2++){ + st_le32( (tbase + memCSR12), rombuf.c[(i+3) + rombuf.c[i+1] + i2]); + } + for (i2 = 0; i2 < rombuf.c[i+1]; i2++){ + st_le32( (tbase + memCSR12), rombuf.c[(i+2) + i2]); + } +} + +static void +dec21140_rxDaemon (void *arg) +{ + unsigned int *tbase; + struct ether_header *eh; + struct dec21140_softc *dp = (struct dec21140_softc *)&dec21140_softc[0]; + struct ifnet *ifp = &dp->arpcom.ac_if; + struct mbuf *m; + struct MD *rmd; + unsigned int len; + char *temp; + rtems_event_set events; + int nbMD; + + tbase = dec21140_softc[0].base ; + + for (;;){ + + rtems_bsdnet_event_receive (INTERRUPT_EVENT, + RTEMS_WAIT|RTEMS_EVENT_ANY, + RTEMS_NO_TIMEOUT, + &events); + rmd = dec21140_softc[0].MDbase; + nbMD = 0; + + while (nbMD < NRXBUFS){ + if ( (rmd->status & 0x80000000) == 0){ + len = (rmd->status >> 16) & 0x7ff; + MGETHDR (m, M_WAIT, MT_DATA); + MCLGET (m, M_WAIT); + m->m_pkthdr.rcvif = ifp; + temp = m->m_data; + m->m_len = m->m_pkthdr.len = len - sizeof(struct ether_header); + memcpy(temp, (char *)((long)(rmd->buf1)-PREP_PCI_DRAM_OFFSET), len); + rmd->status = 0x80000000; + eh = mtod (m, struct ether_header *); + m->m_data += sizeof(struct ether_header); + ether_input (ifp, eh, m); + } + rmd++; + nbMD++; + } + st_le32( (tbase+memCSR7), IT_SETUP); + } +} + +static void +sendpacket (struct ifnet *ifp, struct mbuf *m) +{ + struct dec21140_softc *dp = ifp->if_softc; + volatile struct MD *tmd; + unsigned char *temp; + struct mbuf *n; + unsigned int len; + unsigned int *tbase; + + tbase = dp->base; + + /* + * Waiting for Transmitter ready + */ + tmd = dec21140_softc[0].MDbase + NRXBUFS; + while ( (tmd->status & 0x80000000) != 0 ); + len = 0; + n = m; + temp = (char *)((long)(tmd->buf1)-PREP_PCI_DRAM_OFFSET); + + for (;;){ + len += m->m_len; + memcpy(temp, (char *)m->m_data, m->m_len); + temp += m->m_len ; + if ((m = m->m_next) == NULL) + break; + } + + if (len < ET_MINLEN) len = ET_MINLEN; + tmd->counts = 0xe2000000 | len; + tmd->status = 0x80000000; + + st_le32( (tbase+memCSR1), 0x1); + + m_freem(n); +} + +/* + * Driver transmit daemon + */ +void +dec21140_txDaemon (void *arg) +{ + struct dec21140_softc *sc = (struct dec21140_softc *)arg; + struct ifnet *ifp = &sc->arpcom.ac_if; + struct mbuf *m; + rtems_event_set events; + + for (;;) { + /* + * Wait for packet + */ + + rtems_bsdnet_event_receive (START_TRANSMIT_EVENT, RTEMS_EVENT_ANY | RTEMS_WAIT, RTEMS_NO_TIMEOUT, &events); + + /* + * Send packets till queue is empty + */ + for (;;) { + /* + * Get the next mbuf chain to transmit. + */ + IF_DEQUEUE(&ifp->if_snd, m); + if (!m) + break; + sendpacket (ifp, m); + } + ifp->if_flags &= ~IFF_OACTIVE; + } +} + + +static void +dec21140_start (struct ifnet *ifp) +{ + struct dec21140_softc *sc = ifp->if_softc; + + rtems_event_send (sc->txDaemonTid, START_TRANSMIT_EVENT); + ifp->if_flags |= IFF_OACTIVE; +} + +/* + * Initialize and start the device + */ +static void +dec21140_init (void *arg) +{ + struct dec21140_softc *sc = arg; + struct ifnet *ifp = &sc->arpcom.ac_if; + + if (sc->txDaemonTid == 0) { + + /* + * Set up DEC21140 hardware + */ + dec21140Enet_initialize_hardware (sc); + + /* + * Start driver tasks + */ + sc->rxDaemonTid = rtems_bsdnet_newproc ("DCrx", 4096, + dec21140_rxDaemon, sc); + sc->txDaemonTid = rtems_bsdnet_newproc ("DCtx", 4096, + dec21140_txDaemon, sc); + } + + /* + * Tell the world that we're running. + */ + ifp->if_flags |= IFF_RUNNING; + +} + +/* + * Stop the device + */ +static void +dec21140_stop (struct dec21140_softc *sc) +{ + unsigned int *tbase; + struct ifnet *ifp = &sc->arpcom.ac_if; + + ifp->if_flags &= ~IFF_RUNNING; + + /* + * Stop the transmitter + */ + tbase=dec21140_softc[0].base ; + st_le32( (tbase+memCSR7), NO_IT); + st_le32( (tbase+memCSR6), CSR6_INIT); + free(sc->bufferBase); +} + + +/* + * Show interface statistics + */ +static void +dec21140_stats (struct dec21140_softc *sc) +{ + printf (" Rx Interrupts:%-8lu", sc->rxInterrupts); + printf (" Not First:%-8lu", sc->rxNotFirst); + printf (" Not Last:%-8lu\n", sc->rxNotLast); + printf (" Giant:%-8lu", sc->rxGiant); + printf (" Runt:%-8lu", sc->rxRunt); + printf (" Non-octet:%-8lu\n", sc->rxNonOctet); + printf (" Bad CRC:%-8lu", sc->rxBadCRC); + printf (" Overrun:%-8lu", sc->rxOverrun); + printf (" Collision:%-8lu\n", sc->rxCollision); + + printf (" Tx Interrupts:%-8lu", sc->txInterrupts); + printf (" Deferred:%-8lu", sc->txDeferred); + printf (" Missed Hearbeat:%-8lu\n", sc->txHeartbeat); + printf (" No Carrier:%-8lu", sc->txLostCarrier); + printf ("Retransmit Limit:%-8lu", sc->txRetryLimit); + printf (" Late Collision:%-8lu\n", sc->txLateCollision); + printf (" Underrun:%-8lu", sc->txUnderrun); + printf (" Raw output wait:%-8lu\n", sc->txRawWait); +} + +/* + * Driver ioctl handler + */ +static int +dec21140_ioctl (struct ifnet *ifp, int command, caddr_t data) +{ + struct dec21140_softc *sc = ifp->if_softc; + int error = 0; + + switch (command) { + case SIOCGIFADDR: + case SIOCSIFADDR: + ether_ioctl (ifp, command, data); + break; + + case SIOCSIFFLAGS: + switch (ifp->if_flags & (IFF_UP | IFF_RUNNING)) { + case IFF_RUNNING: + dec21140_stop (sc); + break; + + case IFF_UP: + dec21140_init (sc); + break; + + case IFF_UP | IFF_RUNNING: + dec21140_stop (sc); + dec21140_init (sc); + break; + + default: + break; + } + break; + + case SIO_RTEMS_SHOW_STATS: + dec21140_stats (sc); + break; + + /* + * FIXME: All sorts of multicast commands need to be added here! + */ + default: + error = EINVAL; + break; + } + + return error; +} + +/* + * Attach an DEC21140 driver to the system + */ +int +rtems_dec21140_driver_attach (struct rtems_bsdnet_ifconfig *config) +{ + struct dec21140_softc *sc; + struct ifnet *ifp; + int mtu; + int i; + unsigned char ucSlotNumber, ucFnNumber; + unsigned int ulDeviceID, lvalue, tmp; + unsigned char cvalue; + int value; + char interrupt; + int diag; + + /* + * First, find a DEC board + */ + for(ucSlotNumber=0;ucSlotNumberarpcom.ac_if; + if (ifp->if_softc == NULL) + break; + } + if (i >= NDECDRIVER) { + printk ("Too many DEC drivers.\n"); + return 0; + } + + /* + * Process options + */ + + (void)pci_read_config_dword(0, + ucSlotNumber, + ucFnNumber, + PCI_BASE_ADDRESS_0, + &lvalue); + + sc->port = lvalue & (unsigned int)(~IO_MASK); + + (void)pci_read_config_dword(0, + ucSlotNumber, + ucFnNumber, + PCI_BASE_ADDRESS_1 , + &lvalue); + + + tmp = (unsigned int)(lvalue & (unsigned int)(~MEM_MASK)) + + (unsigned int)PREP_ISA_MEM_BASE; + sc->base = (unsigned int *)(tmp); + + (void)pci_read_config_byte(0, + ucSlotNumber, + ucFnNumber, + PCI_INTERRUPT_LINE, + &cvalue); + sc->irqInfo.name = (rtems_irq_symbolic_name)cvalue; + + if (config->hardware_address) { + memcpy (sc->arpcom.ac_enaddr, config->hardware_address, + ETHER_ADDR_LEN); + } + else { + memset (sc->arpcom.ac_enaddr, 0x08,ETHER_ADDR_LEN); + } + if (config->mtu) + mtu = config->mtu; + else + mtu = ETHERMTU; + + sc->acceptBroadcast = !config->ignore_broadcast; + + /* + * Set up network interface values + */ + ifp->if_softc = sc; + ifp->if_unit = i + 1; + ifp->if_name = "dc"; + ifp->if_mtu = mtu; + ifp->if_init = dec21140_init; + ifp->if_ioctl = dec21140_ioctl; + ifp->if_start = dec21140_start; + ifp->if_output = ether_output; + ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX; + if (ifp->if_snd.ifq_maxlen == 0) + ifp->if_snd.ifq_maxlen = ifqmaxlen; + + /* + * Attach the interface + */ + if_attach (ifp); + ether_ifattach (ifp); + + return 1; +}; + diff --git a/c/src/lib/libbsp/powerpc/motorola_powerpc/bootloader/README b/c/src/lib/libbsp/powerpc/motorola_powerpc/bootloader/README new file mode 100644 index 0000000000..6d36a152ba --- /dev/null +++ b/c/src/lib/libbsp/powerpc/motorola_powerpc/bootloader/README @@ -0,0 +1,41 @@ +# +# $Id$ +# + +The code in this directory has been taken WITH PERMISSION from +Gabriel Paubert, paubert@iram.es. The main reason for having +a separate bootloader for PreP compliant firmware is that the +initial code is relocated by firmware at an unknow address +(actually 0x5000 on motorola MCP750) and that as Gabriel I +think having a relocatable bootloder code is a must. + +So the way of building a binary executable that can be booted via +hard disk or network boot goes like this : + + - make a RTEMS executable, + - put is as data section in the bootloder binary, + - relink the loader (see make-exe macros for details), + +I would like to thank Gabriel for his support and his code. +The original code can be found in form of a patch to official linux +kernel at (I insist not vger ppc kernel or Imac ppc kernels!!) : + + + +After applying the patch, the code is located in a new directory +called prepboot. + +(NB : note use ftp not netscape...) + +Note that the actual code differs a lot since Gabriel choose to use +a CHRP compliant mapping instead of a Prep Mapping to save +BATs. I had no time to upgrade the code to its new one allthough +I agree it should be done... + +I have also splitted the original code to have a more modular +design enabling to reuse code between the loader and RTEMS +initialization (e.g printk, ...). + +Eric Valette (valette@crf.canon.fr) + + diff --git a/c/src/lib/libbsp/powerpc/motorola_powerpc/dec21140/dec21140.c b/c/src/lib/libbsp/powerpc/motorola_powerpc/dec21140/dec21140.c new file mode 100644 index 0000000000..b5a602645d --- /dev/null +++ b/c/src/lib/libbsp/powerpc/motorola_powerpc/dec21140/dec21140.c @@ -0,0 +1,907 @@ +/* + * RTEMS driver for TULIP based Ethernet Controller + * + * Copyright (C) 1999 Emmanuel Raguet. raguet@crf.canon.fr + * + * The license and distribution terms for this file may be + * found in found in the file LICENSE in this distribution or at + * http://www.OARcorp.com/rtems/license.html. + * + * $Id$ + */ + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include + +#ifdef malloc +#undef malloc +#endif +#ifdef free +#undef free +#endif + +#define DEC_DEBUG + +#define PCI_INVALID_VENDORDEVICEID 0xffffffff +#define PCI_VENDOR_ID_DEC 0x1011 +#define PCI_DEVICE_ID_DEC_TULIP_FAST 0x0009 + +#define IO_MASK 0x3 +#define MEM_MASK 0xF +#define MASK_OFFSET 0xF + +/* command and status registers, 32-bit access, only if IO-ACCESS */ +#define ioCSR0 0x00 /* bus mode register */ +#define ioCSR1 0x08 /* transmit poll demand */ +#define ioCSR2 0x10 /* receive poll demand */ +#define ioCSR3 0x18 /* receive list base address */ +#define ioCSR4 0x20 /* transmit list base address */ +#define ioCSR5 0x28 /* status register */ +#define ioCSR6 0x30 /* operation mode register */ +#define ioCSR7 0x38 /* interrupt mask register */ +#define ioCSR8 0x40 /* missed frame counter */ +#define ioCSR9 0x48 /* Ethernet ROM register */ +#define ioCSR10 0x50 /* reserved */ +#define ioCSR11 0x58 /* full-duplex register */ +#define ioCSR12 0x60 /* SIA status register */ +#define ioCSR13 0x68 +#define ioCSR14 0x70 +#define ioCSR15 0x78 /* SIA general register */ + +/* command and status registers, 32-bit access, only if MEMORY-ACCESS */ +#define memCSR0 0x00 /* bus mode register */ +#define memCSR1 0x02 /* transmit poll demand */ +#define memCSR2 0x04 /* receive poll demand */ +#define memCSR3 0x06 /* receive list base address */ +#define memCSR4 0x08 /* transmit list base address */ +#define memCSR5 0x0A /* status register */ +#define memCSR6 0x0C /* operation mode register */ +#define memCSR7 0x0E /* interrupt mask register */ +#define memCSR8 0x10 /* missed frame counter */ +#define memCSR9 0x12 /* Ethernet ROM register */ +#define memCSR10 0x14 /* reserved */ +#define memCSR11 0x16 /* full-duplex register */ +#define memCSR12 0x18 /* SIA status register */ +#define memCSR13 0x1A +#define memCSR14 0x1C +#define memCSR15 0x1E /* SIA general register */ + +#define DEC_REGISTER_SIZE 0x100 /* to reserve virtual memory */ + +#define RESET_CHIP 0x00000001 +#define CSR0_MODE 0x01b08000 /* 01a08000 */ +#define ROM_ADDRESS 0x00004800 +#define CSR6_INIT 0x020c0000 /* 020c0000 */ +#define CSR6_TX 0x00002000 +#define CSR6_TXRX 0x00002002 +#define IT_SETUP 0x00010040 /* 0001ebef */ +#define CLEAR_IT 0xFFFFFFFF +#define NO_IT 0x00000000 + +#define NRXBUFS 7 /* number of receive buffers */ +#define NTXBUFS 1 /* number of transmit buffers */ + +/* message descriptor entry */ +struct MD { + volatile unsigned long status; + volatile unsigned long counts; + unsigned long buf1, buf2; +}; + +/* + * Number of WDs supported by this driver + */ +#define NDECDRIVER 1 + +/* + * Receive buffer size -- Allow for a full ethernet packet including CRC + */ +#define RBUF_SIZE 1520 + +#define ET_MINLEN 60 /* minimum message length */ + +/* + * RTEMS event used by interrupt handler to signal driver tasks. + * This must not be any of the events used by the network task synchronization. + */ +#define INTERRUPT_EVENT RTEMS_EVENT_1 + +/* + * RTEMS event used to start transmit daemon. + * This must not be the same as INTERRUPT_EVENT. + */ +#define START_TRANSMIT_EVENT RTEMS_EVENT_2 + +#if (MCLBYTES < RBUF_SIZE) +# error "Driver must have MCLBYTES > RBUF_SIZE" +#endif + +/* + * Per-device data + */ + struct dec21140_softc { + struct arpcom arpcom; + rtems_irq_connect_data irqInfo; + struct MD *MDbase; + char *bufferBase; + int acceptBroadcast; + int rxBdCount; + int txBdCount; + rtems_id rxDaemonTid; + rtems_id txDaemonTid; + + unsigned int port; + unsigned int *base; + unsigned long bpar; + + /* + * Statistics + */ + unsigned long rxInterrupts; + unsigned long rxNotFirst; + unsigned long rxNotLast; + unsigned long rxGiant; + unsigned long rxNonOctet; + unsigned long rxRunt; + unsigned long rxBadCRC; + unsigned long rxOverrun; + unsigned long rxCollision; + + unsigned long txInterrupts; + unsigned long txDeferred; + unsigned long txHeartbeat; + unsigned long txLateCollision; + unsigned long txRetryLimit; + unsigned long txUnderrun; + unsigned long txLostCarrier; + unsigned long txRawWait; +}; + +static struct dec21140_softc dec21140_softc[NDECDRIVER]; + +/* + * DEC21140 interrupt handler + */ +static rtems_isr +dec21140Enet_interrupt_handler (rtems_vector_number v) +{ + unsigned int *tbase; + unsigned long status; + + unsigned int sc; + + tbase = dec21140_softc[0].base ; + + /* + * Read status + */ + st_le32((tbase+memCSR7), NO_IT); + status = ld_le32(tbase+memCSR5); + st_le32((tbase+memCSR5), CLEAR_IT); + + /* + * Frame received? + */ + if (status & 0x00000040){ + dec21140_softc[0].rxInterrupts++; + sc = rtems_event_send (dec21140_softc[0].rxDaemonTid, INTERRUPT_EVENT); + } +} + +static void nopOn(const rtems_irq_connect_data* notUsed) +{ + /* + * code should be moved from dec21140Enet_initialize_hardware + * to this location + */ +} + +static int dec21140IsOn(const rtems_irq_connect_data* irq) +{ + return BSP_irq_enabled_at_i8259s (irq->name); +} + +/* + * Read and write the MII registers using software-generated serial + * MDIO protocol. + */ +#define MDIO_SHIFT_CLK 0x10000 +#define MDIO_DATA_WRITE0 0x00000 +#define MDIO_DATA_WRITE1 0x20000 +#define MDIO_ENB 0x00000 +#define MDIO_ENB_IN 0x40000 +#define MDIO_DATA_READ 0x80000 + +static int mdio_read(unsigned int *ioaddr, int phy_id, int location) +{ + int i, i3; + int read_cmd = (0xf6 << 10) | (phy_id << 5) | location; + unsigned short retval = 0; + + /* Establish sync by sending at least 32 logic ones. */ + for (i = 32; i >= 0; i--) { + st_le32(ioaddr, MDIO_ENB | MDIO_DATA_WRITE1); + for(i3=0; i3<1000; i3++); + st_le32(ioaddr, MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK); + for(i3=0; i3<1000; i3++); + } + /* Shift the read command bits out. */ + for (i = 17; i >= 0; i--) { + int dataval = (read_cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0; + st_le32(ioaddr, dataval); + for(i3=0; i3<1000; i3++); + st_le32(ioaddr, dataval | MDIO_SHIFT_CLK); + for(i3=0; i3<1000; i3++); + st_le32(ioaddr, dataval); + for(i3=0; i3<1000; i3++); + } + st_le32(ioaddr, MDIO_ENB_IN | MDIO_SHIFT_CLK); + for(i3=0; i3<1000; i3++); + st_le32(ioaddr, MDIO_ENB_IN); + + for (i = 16; i > 0; i--) { + st_le32(ioaddr, MDIO_ENB_IN | MDIO_SHIFT_CLK); + for(i3=0; i3<1000; i3++); + retval = (retval << 1) | ((ld_le32(ioaddr) & MDIO_DATA_READ) ? 1 : 0); + st_le32(ioaddr, MDIO_ENB_IN); + for(i3=0; i3<1000; i3++); + } + /* Clear out extra bits. */ + for (i = 16; i > 0; i--) { + st_le32(ioaddr, MDIO_ENB_IN | MDIO_SHIFT_CLK); + for(i3=0; i3<1000; i3++); + st_le32(ioaddr, MDIO_ENB_IN); + for(i3=0; i3<1000; i3++); + } + return ( ((retval<<8)&0xff00) | ((retval>>8)&0xff) ); +} + +static int mdio_write(unsigned int *ioaddr, int phy_id, int location, int value) +{ + int i, i3; + int cmd = (0x5002 << 16) | (phy_id << 23) | (location << 18) | value; + + /* Establish sync by sending at least 32 logic ones. */ + for (i = 32; i >= 0; i--) { + st_le32(ioaddr, MDIO_ENB | MDIO_DATA_WRITE1); + for(i3=0; i3<1000; i3++); + st_le32(ioaddr, MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK); + for(i3=0; i3<1000; i3++); + } + /* Shift the read command bits out. */ + for (i = 31; i >= 0; i--) { + int dataval = (cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0; + st_le32(ioaddr, dataval); + for(i3=0; i3<1000; i3++); + st_le32(ioaddr, dataval | MDIO_SHIFT_CLK); + for(i3=0; i3<1000; i3++); + } + + /* Clear out extra bits. */ + for (i = 2; i > 0; i--) { + st_le32(ioaddr, MDIO_ENB_IN); + for(i3=0; i3<1000; i3++); + st_le32(ioaddr, MDIO_ENB_IN | MDIO_SHIFT_CLK); + for(i3=0; i3<1000; i3++); + } + return 0; + + +} + +/* + * This routine reads a word (16 bits) from the serial EEPROM. + */ +/* EEPROM_Ctrl bits. */ +#define EE_SHIFT_CLK 0x02 /* EEPROM shift clock. */ +#define EE_CS 0x01 /* EEPROM chip select. */ +#define EE_DATA_WRITE 0x04 /* EEPROM chip data in. */ +#define EE_WRITE_0 0x01 +#define EE_WRITE_1 0x05 +#define EE_DATA_READ 0x08 /* EEPROM chip data out. */ +#define EE_ENB (0x4800 | EE_CS) + +/* The EEPROM commands include the alway-set leading bit. */ +#define EE_WRITE_CMD (5 << 6) +#define EE_READ_CMD (6 << 6) +#define EE_ERASE_CMD (7 << 6) + +static int eeget16(unsigned int *ioaddr, int location) +{ + int i, i3; + unsigned short retval = 0; + int read_cmd = location | EE_READ_CMD; + + st_le32(ioaddr, EE_ENB & ~EE_CS); + st_le32(ioaddr, EE_ENB); + + /* Shift the read command bits out. */ + for (i = 10; i >= 0; i--) { + short dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0; + st_le32(ioaddr, EE_ENB | dataval); + for (i3=0; i3<1000; i3++) ; + st_le32(ioaddr, EE_ENB | dataval | EE_SHIFT_CLK); + for (i3=0; i3<1000; i3++) ; + st_le32(ioaddr, EE_ENB | dataval); /* Finish EEPROM a clock tick. */ + for (i3=0; i3<1000; i3++) ; + } + st_le32(*ioaddr, EE_ENB); + + for (i = 16; i > 0; i--) { + st_le32(ioaddr, EE_ENB | EE_SHIFT_CLK); + for (i3=0; i3<1000; i3++) ; + retval = (retval << 1) | ((ld_le32(ioaddr) & EE_DATA_READ) ? 1 : 0); + st_le32(ioaddr, EE_ENB); + for (i3=0; i3<1000; i3++) ; + } + + /* Terminate the EEPROM access. */ + st_le32(*ioaddr, EE_ENB & ~EE_CS); + return ( ((retval<<8)&0xff00) | ((retval>>8)&0xff) ); +} + +/* + * Initialize the ethernet hardware + */ +static void +dec21140Enet_initialize_hardware (struct dec21140_softc *sc) +{ + rtems_status_code st; + unsigned int *tbase; + union {char c[64]; unsigned short s[32];} rombuf; + int i, i2, i3; + char *cp, direction, *setup_frm, *eaddrs; + unsigned long csr12_val, mii_reg0; + unsigned char *buffer; + struct MD *rmd; + + + tbase = sc->base; + + + + /* + * WARNING : First write in CSR6 + * Then Reset the chip ( 1 in CSR0) + */ + + st_le32( (tbase+memCSR6), CSR6_INIT); + st_le32( (tbase+memCSR0), RESET_CHIP); + for(i3=0; i3<1000; i3++); + + /* + * Init CSR0 + */ + st_le32( (tbase+memCSR0), CSR0_MODE); + + csr12_val = ld_le32( (tbase+memCSR8) ); + + for (i=0; i<32; i++){ + rombuf.s[i] = eeget16(tbase+memCSR9, i); + } + memcpy (sc->arpcom.ac_enaddr, rombuf.c+20, ETHER_ADDR_LEN); + + mii_reg0 = mdio_read(tbase+memCSR9, 0, 0); + mdio_write(tbase+memCSR9, 0, 0, mii_reg0 | 0x1000); + +#ifdef DEC_DEBUG + printk("DC21140 %x:%x:%x:%x:%x:%x IRQ %d IO %x M %x .........\n", + sc->arpcom.ac_enaddr[0], sc->arpcom.ac_enaddr[1], + sc->arpcom.ac_enaddr[2], sc->arpcom.ac_enaddr[3], + sc->arpcom.ac_enaddr[4], sc->arpcom.ac_enaddr[5], + sc->irqInfo.name, sc->port, sc->base); +#endif + + /* + * Init RX ring + */ + sc->rxBdCount = 0; + cp = (char *)malloc((NRXBUFS+NTXBUFS)*(sizeof(struct MD)+ RBUF_SIZE) + PPC_CACHE_ALIGNMENT); + sc->bufferBase = cp; + cp += (PPC_CACHE_ALIGNMENT - (int)cp) & MASK_OFFSET; +#ifdef PCI_BRIDGE_DOES_NOT_ENSURE_CACHE_COHERENCY_FOR_DMA + if (_CPU_is_paging_enabled()) + _CPU_change_memory_mapping_attribute + (NULL, cp, + (NRXBUFS+NTXBUFS)*(sizeof(struct MD)+ RBUF_SIZE), + PTE_CACHE_DISABLE | PTE_WRITABLE); +#endif + rmd = (struct MD*)cp; + sc->MDbase = rmd; + buffer = cp + ((NRXBUFS+NTXBUFS)*sizeof(struct MD)); + st_le32( (tbase+memCSR3), (long)((long)(sc->MDbase) + PREP_PCI_DRAM_OFFSET)); + for (i=0 ; ibuf2 = 0; + rmd->buf1 = (unsigned long)(buffer + (i*RBUF_SIZE) + PREP_PCI_DRAM_OFFSET); + if (i == NRXBUFS-1) + rmd->counts = 0xfec00000 | (RBUF_SIZE); + else + rmd->counts = 0xfcc00000 | (RBUF_SIZE); + rmd->status = 0x80000000; + rmd++; + } + + /* + * Init TX ring + */ + sc->txBdCount = 0; + st_le32( (tbase+memCSR4), (long)((long)(rmd) + PREP_PCI_DRAM_OFFSET)); + rmd->buf2 = 0; + rmd->buf1 = (unsigned long)(buffer + (NRXBUFS*RBUF_SIZE) + PREP_PCI_DRAM_OFFSET); + rmd->counts = 0x62000000; + rmd->status = 0x0; + + /* + * Set up interrupts + */ + st_le32( (tbase+memCSR5), IT_SETUP); + st_le32( (tbase+memCSR7), IT_SETUP); + + sc->irqInfo.hdl = (rtems_irq_hdl)dec21140Enet_interrupt_handler; + sc->irqInfo.on = nopOn; + sc->irqInfo.off = nopOn; + sc->irqInfo.isOn = dec21140IsOn; + st = BSP_install_rtems_irq_handler (&sc->irqInfo); + if (!st) + rtems_panic ("Can't attach DEC21140 interrupt handler for irq %d\n", + sc->irqInfo.name); + + /* + * Start TX for setup frame + */ + st_le32( (tbase+memCSR6), CSR6_INIT | CSR6_TX); + + /* + * Build setup frame + */ + setup_frm = (char *)((long)(rmd->buf1) - PREP_PCI_DRAM_OFFSET); + eaddrs = (char *)(sc->arpcom.ac_enaddr); + /* Fill the buffer with our physical address. */ + for (i = 1; i < 16; i++) { + *setup_frm++ = eaddrs[0]; + *setup_frm++ = eaddrs[1]; + *setup_frm++ = eaddrs[0]; + *setup_frm++ = eaddrs[1]; + *setup_frm++ = eaddrs[2]; + *setup_frm++ = eaddrs[3]; + *setup_frm++ = eaddrs[2]; + *setup_frm++ = eaddrs[3]; + *setup_frm++ = eaddrs[4]; + *setup_frm++ = eaddrs[5]; + *setup_frm++ = eaddrs[4]; + *setup_frm++ = eaddrs[5]; + } + /* Add the broadcast address when doing perfect filtering */ + memset(setup_frm, 0xff, 12); + rmd->counts = 0x0a000000 | 192 ; + rmd->status = 0x80000000; + st_le32( (tbase+memCSR1), 1); + while (rmd->status != 0x7fffffff); + + /* + * Enable RX and TX + */ + st_le32( (unsigned int*)(tbase+memCSR6), CSR6_INIT | CSR6_TXRX); + + /* + * Set up PHY + */ + + i = rombuf.c[27]; + i+=2; + direction = rombuf.c[i]; + i +=4; + st_le32( (tbase+memCSR12), direction | 0x100); + for (i2 = 0; i2 < rombuf.c[(i+2) + rombuf.c[i+1]]; i2++){ + st_le32( (tbase + memCSR12), rombuf.c[(i+3) + rombuf.c[i+1] + i2]); + } + for (i2 = 0; i2 < rombuf.c[i+1]; i2++){ + st_le32( (tbase + memCSR12), rombuf.c[(i+2) + i2]); + } +} + +static void +dec21140_rxDaemon (void *arg) +{ + unsigned int *tbase; + struct ether_header *eh; + struct dec21140_softc *dp = (struct dec21140_softc *)&dec21140_softc[0]; + struct ifnet *ifp = &dp->arpcom.ac_if; + struct mbuf *m; + struct MD *rmd; + unsigned int len; + char *temp; + rtems_event_set events; + int nbMD; + + tbase = dec21140_softc[0].base ; + + for (;;){ + + rtems_bsdnet_event_receive (INTERRUPT_EVENT, + RTEMS_WAIT|RTEMS_EVENT_ANY, + RTEMS_NO_TIMEOUT, + &events); + rmd = dec21140_softc[0].MDbase; + nbMD = 0; + + while (nbMD < NRXBUFS){ + if ( (rmd->status & 0x80000000) == 0){ + len = (rmd->status >> 16) & 0x7ff; + MGETHDR (m, M_WAIT, MT_DATA); + MCLGET (m, M_WAIT); + m->m_pkthdr.rcvif = ifp; + temp = m->m_data; + m->m_len = m->m_pkthdr.len = len - sizeof(struct ether_header); + memcpy(temp, (char *)((long)(rmd->buf1)-PREP_PCI_DRAM_OFFSET), len); + rmd->status = 0x80000000; + eh = mtod (m, struct ether_header *); + m->m_data += sizeof(struct ether_header); + ether_input (ifp, eh, m); + } + rmd++; + nbMD++; + } + st_le32( (tbase+memCSR7), IT_SETUP); + } +} + +static void +sendpacket (struct ifnet *ifp, struct mbuf *m) +{ + struct dec21140_softc *dp = ifp->if_softc; + volatile struct MD *tmd; + unsigned char *temp; + struct mbuf *n; + unsigned int len; + unsigned int *tbase; + + tbase = dp->base; + + /* + * Waiting for Transmitter ready + */ + tmd = dec21140_softc[0].MDbase + NRXBUFS; + while ( (tmd->status & 0x80000000) != 0 ); + len = 0; + n = m; + temp = (char *)((long)(tmd->buf1)-PREP_PCI_DRAM_OFFSET); + + for (;;){ + len += m->m_len; + memcpy(temp, (char *)m->m_data, m->m_len); + temp += m->m_len ; + if ((m = m->m_next) == NULL) + break; + } + + if (len < ET_MINLEN) len = ET_MINLEN; + tmd->counts = 0xe2000000 | len; + tmd->status = 0x80000000; + + st_le32( (tbase+memCSR1), 0x1); + + m_freem(n); +} + +/* + * Driver transmit daemon + */ +void +dec21140_txDaemon (void *arg) +{ + struct dec21140_softc *sc = (struct dec21140_softc *)arg; + struct ifnet *ifp = &sc->arpcom.ac_if; + struct mbuf *m; + rtems_event_set events; + + for (;;) { + /* + * Wait for packet + */ + + rtems_bsdnet_event_receive (START_TRANSMIT_EVENT, RTEMS_EVENT_ANY | RTEMS_WAIT, RTEMS_NO_TIMEOUT, &events); + + /* + * Send packets till queue is empty + */ + for (;;) { + /* + * Get the next mbuf chain to transmit. + */ + IF_DEQUEUE(&ifp->if_snd, m); + if (!m) + break; + sendpacket (ifp, m); + } + ifp->if_flags &= ~IFF_OACTIVE; + } +} + + +static void +dec21140_start (struct ifnet *ifp) +{ + struct dec21140_softc *sc = ifp->if_softc; + + rtems_event_send (sc->txDaemonTid, START_TRANSMIT_EVENT); + ifp->if_flags |= IFF_OACTIVE; +} + +/* + * Initialize and start the device + */ +static void +dec21140_init (void *arg) +{ + struct dec21140_softc *sc = arg; + struct ifnet *ifp = &sc->arpcom.ac_if; + + if (sc->txDaemonTid == 0) { + + /* + * Set up DEC21140 hardware + */ + dec21140Enet_initialize_hardware (sc); + + /* + * Start driver tasks + */ + sc->rxDaemonTid = rtems_bsdnet_newproc ("DCrx", 4096, + dec21140_rxDaemon, sc); + sc->txDaemonTid = rtems_bsdnet_newproc ("DCtx", 4096, + dec21140_txDaemon, sc); + } + + /* + * Tell the world that we're running. + */ + ifp->if_flags |= IFF_RUNNING; + +} + +/* + * Stop the device + */ +static void +dec21140_stop (struct dec21140_softc *sc) +{ + unsigned int *tbase; + struct ifnet *ifp = &sc->arpcom.ac_if; + + ifp->if_flags &= ~IFF_RUNNING; + + /* + * Stop the transmitter + */ + tbase=dec21140_softc[0].base ; + st_le32( (tbase+memCSR7), NO_IT); + st_le32( (tbase+memCSR6), CSR6_INIT); + free(sc->bufferBase); +} + + +/* + * Show interface statistics + */ +static void +dec21140_stats (struct dec21140_softc *sc) +{ + printf (" Rx Interrupts:%-8lu", sc->rxInterrupts); + printf (" Not First:%-8lu", sc->rxNotFirst); + printf (" Not Last:%-8lu\n", sc->rxNotLast); + printf (" Giant:%-8lu", sc->rxGiant); + printf (" Runt:%-8lu", sc->rxRunt); + printf (" Non-octet:%-8lu\n", sc->rxNonOctet); + printf (" Bad CRC:%-8lu", sc->rxBadCRC); + printf (" Overrun:%-8lu", sc->rxOverrun); + printf (" Collision:%-8lu\n", sc->rxCollision); + + printf (" Tx Interrupts:%-8lu", sc->txInterrupts); + printf (" Deferred:%-8lu", sc->txDeferred); + printf (" Missed Hearbeat:%-8lu\n", sc->txHeartbeat); + printf (" No Carrier:%-8lu", sc->txLostCarrier); + printf ("Retransmit Limit:%-8lu", sc->txRetryLimit); + printf (" Late Collision:%-8lu\n", sc->txLateCollision); + printf (" Underrun:%-8lu", sc->txUnderrun); + printf (" Raw output wait:%-8lu\n", sc->txRawWait); +} + +/* + * Driver ioctl handler + */ +static int +dec21140_ioctl (struct ifnet *ifp, int command, caddr_t data) +{ + struct dec21140_softc *sc = ifp->if_softc; + int error = 0; + + switch (command) { + case SIOCGIFADDR: + case SIOCSIFADDR: + ether_ioctl (ifp, command, data); + break; + + case SIOCSIFFLAGS: + switch (ifp->if_flags & (IFF_UP | IFF_RUNNING)) { + case IFF_RUNNING: + dec21140_stop (sc); + break; + + case IFF_UP: + dec21140_init (sc); + break; + + case IFF_UP | IFF_RUNNING: + dec21140_stop (sc); + dec21140_init (sc); + break; + + default: + break; + } + break; + + case SIO_RTEMS_SHOW_STATS: + dec21140_stats (sc); + break; + + /* + * FIXME: All sorts of multicast commands need to be added here! + */ + default: + error = EINVAL; + break; + } + + return error; +} + +/* + * Attach an DEC21140 driver to the system + */ +int +rtems_dec21140_driver_attach (struct rtems_bsdnet_ifconfig *config) +{ + struct dec21140_softc *sc; + struct ifnet *ifp; + int mtu; + int i; + unsigned char ucSlotNumber, ucFnNumber; + unsigned int ulDeviceID, lvalue, tmp; + unsigned char cvalue; + int value; + char interrupt; + int diag; + + /* + * First, find a DEC board + */ + for(ucSlotNumber=0;ucSlotNumberarpcom.ac_if; + if (ifp->if_softc == NULL) + break; + } + if (i >= NDECDRIVER) { + printk ("Too many DEC drivers.\n"); + return 0; + } + + /* + * Process options + */ + + (void)pci_read_config_dword(0, + ucSlotNumber, + ucFnNumber, + PCI_BASE_ADDRESS_0, + &lvalue); + + sc->port = lvalue & (unsigned int)(~IO_MASK); + + (void)pci_read_config_dword(0, + ucSlotNumber, + ucFnNumber, + PCI_BASE_ADDRESS_1 , + &lvalue); + + + tmp = (unsigned int)(lvalue & (unsigned int)(~MEM_MASK)) + + (unsigned int)PREP_ISA_MEM_BASE; + sc->base = (unsigned int *)(tmp); + + (void)pci_read_config_byte(0, + ucSlotNumber, + ucFnNumber, + PCI_INTERRUPT_LINE, + &cvalue); + sc->irqInfo.name = (rtems_irq_symbolic_name)cvalue; + + if (config->hardware_address) { + memcpy (sc->arpcom.ac_enaddr, config->hardware_address, + ETHER_ADDR_LEN); + } + else { + memset (sc->arpcom.ac_enaddr, 0x08,ETHER_ADDR_LEN); + } + if (config->mtu) + mtu = config->mtu; + else + mtu = ETHERMTU; + + sc->acceptBroadcast = !config->ignore_broadcast; + + /* + * Set up network interface values + */ + ifp->if_softc = sc; + ifp->if_unit = i + 1; + ifp->if_name = "dc"; + ifp->if_mtu = mtu; + ifp->if_init = dec21140_init; + ifp->if_ioctl = dec21140_ioctl; + ifp->if_start = dec21140_start; + ifp->if_output = ether_output; + ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX; + if (ifp->if_snd.ifq_maxlen == 0) + ifp->if_snd.ifq_maxlen = ifqmaxlen; + + /* + * Attach the interface + */ + if_attach (ifp); + ether_ifattach (ifp); + + return 1; +}; + -- cgit v1.2.3