forked from Imagelibrary/rtems
New files missed in previous addition.
This commit is contained in:
41
c/src/lib/libbsp/powerpc/mcp750/bootloader/README
Normal file
41
c/src/lib/libbsp/powerpc/mcp750/bootloader/README
Normal file
@@ -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!!) :
|
||||||
|
|
||||||
|
<ftp://vlab1.iram.es/pub/linux-2.2/>
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
|
||||||
907
c/src/lib/libbsp/powerpc/mcp750/dec21140/dec21140.c
Normal file
907
c/src/lib/libbsp/powerpc/mcp750/dec21140/dec21140.c
Normal file
@@ -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 <bsp.h>
|
||||||
|
#include <bsp/pci.h>
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <rtems/error.h>
|
||||||
|
#include <rtems/rtems_bsdnet.h>
|
||||||
|
|
||||||
|
#include <libcpu/cpu.h>
|
||||||
|
#include <libcpu/io.h>
|
||||||
|
#include <libcpu/byteorder.h>
|
||||||
|
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include <sys/mbuf.h>
|
||||||
|
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/sockio.h>
|
||||||
|
#include <net/if.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <netinet/if_ether.h>
|
||||||
|
|
||||||
|
#include <bsp/irq.h>
|
||||||
|
|
||||||
|
#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 ; i<NRXBUFS; i++){
|
||||||
|
rmd->buf2 = 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;ucSlotNumber<PCI_MAX_DEVICES;ucSlotNumber++) {
|
||||||
|
for(ucFnNumber=0;ucFnNumber<PCI_MAX_FUNCTIONS;ucFnNumber++) {
|
||||||
|
(void)pci_read_config_dword(0,
|
||||||
|
ucSlotNumber,
|
||||||
|
ucFnNumber,
|
||||||
|
PCI_VENDOR_ID,
|
||||||
|
&ulDeviceID);
|
||||||
|
if(ulDeviceID==PCI_INVALID_VENDORDEVICEID) {
|
||||||
|
/*
|
||||||
|
* This slot is empty
|
||||||
|
*/
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (ulDeviceID == ((PCI_DEVICE_ID_DEC_TULIP_FAST<<16) + PCI_VENDOR_ID_DEC))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (ulDeviceID == ((PCI_DEVICE_ID_DEC_TULIP_FAST<<16) + PCI_VENDOR_ID_DEC)){
|
||||||
|
printk("DEC Adapter found !!\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ulDeviceID==PCI_INVALID_VENDORDEVICEID)
|
||||||
|
rtems_panic("DEC PCI board not found !!\n");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Find a free driver
|
||||||
|
*/
|
||||||
|
for (i = 0 ; i < NDECDRIVER ; i++) {
|
||||||
|
sc = &dec21140_softc[i];
|
||||||
|
ifp = &sc->arpcom.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;
|
||||||
|
};
|
||||||
|
|
||||||
41
c/src/lib/libbsp/powerpc/motorola_powerpc/bootloader/README
Normal file
41
c/src/lib/libbsp/powerpc/motorola_powerpc/bootloader/README
Normal file
@@ -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!!) :
|
||||||
|
|
||||||
|
<ftp://vlab1.iram.es/pub/linux-2.2/>
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
|
||||||
907
c/src/lib/libbsp/powerpc/motorola_powerpc/dec21140/dec21140.c
Normal file
907
c/src/lib/libbsp/powerpc/motorola_powerpc/dec21140/dec21140.c
Normal file
@@ -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 <bsp.h>
|
||||||
|
#include <bsp/pci.h>
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <rtems/error.h>
|
||||||
|
#include <rtems/rtems_bsdnet.h>
|
||||||
|
|
||||||
|
#include <libcpu/cpu.h>
|
||||||
|
#include <libcpu/io.h>
|
||||||
|
#include <libcpu/byteorder.h>
|
||||||
|
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include <sys/mbuf.h>
|
||||||
|
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/sockio.h>
|
||||||
|
#include <net/if.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <netinet/if_ether.h>
|
||||||
|
|
||||||
|
#include <bsp/irq.h>
|
||||||
|
|
||||||
|
#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 ; i<NRXBUFS; i++){
|
||||||
|
rmd->buf2 = 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;ucSlotNumber<PCI_MAX_DEVICES;ucSlotNumber++) {
|
||||||
|
for(ucFnNumber=0;ucFnNumber<PCI_MAX_FUNCTIONS;ucFnNumber++) {
|
||||||
|
(void)pci_read_config_dword(0,
|
||||||
|
ucSlotNumber,
|
||||||
|
ucFnNumber,
|
||||||
|
PCI_VENDOR_ID,
|
||||||
|
&ulDeviceID);
|
||||||
|
if(ulDeviceID==PCI_INVALID_VENDORDEVICEID) {
|
||||||
|
/*
|
||||||
|
* This slot is empty
|
||||||
|
*/
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (ulDeviceID == ((PCI_DEVICE_ID_DEC_TULIP_FAST<<16) + PCI_VENDOR_ID_DEC))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (ulDeviceID == ((PCI_DEVICE_ID_DEC_TULIP_FAST<<16) + PCI_VENDOR_ID_DEC)){
|
||||||
|
printk("DEC Adapter found !!\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ulDeviceID==PCI_INVALID_VENDORDEVICEID)
|
||||||
|
rtems_panic("DEC PCI board not found !!\n");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Find a free driver
|
||||||
|
*/
|
||||||
|
for (i = 0 ; i < NDECDRIVER ; i++) {
|
||||||
|
sc = &dec21140_softc[i];
|
||||||
|
ifp = &sc->arpcom.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;
|
||||||
|
};
|
||||||
|
|
||||||
Reference in New Issue
Block a user