summaryrefslogtreecommitdiffstats
path: root/bsps/shared/net/smc91111.c
diff options
context:
space:
mode:
Diffstat (limited to 'bsps/shared/net/smc91111.c')
-rw-r--r--bsps/shared/net/smc91111.c1653
1 files changed, 0 insertions, 1653 deletions
diff --git a/bsps/shared/net/smc91111.c b/bsps/shared/net/smc91111.c
deleted file mode 100644
index 61703c7334..0000000000
--- a/bsps/shared/net/smc91111.c
+++ /dev/null
@@ -1,1653 +0,0 @@
-#include <machine/rtems-bsd-kernel-space.h>
-
-#include <rtems.h>
-#include <errno.h>
-
-#include <bsp.h>
-
-/*
- * This driver currently only supports SPARC with the old style
- * exception processing and the Phytec Phycore MPC5554.
- * This test keeps it from being compiled on systems which haven't been
- * tested.
- *
- */
-
-#if defined(HAS_SMC91111)
- #define SMC91111_SUPPORTED
-#endif
-
-#if defined(HAS_SMC91111)
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <stdarg.h>
-#include <inttypes.h>
-#include <rtems/error.h>
-#include <rtems/rtems_bsdnet.h>
-#include <rtems/irq-extension.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>
-
-#define SMC91111_INTERRUPT_EVENT RTEMS_EVENT_1 /* 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 SMC91111_START_TRANSMIT_EVENT RTEMS_EVENT_2 /* RTEMS event used to start transmit/receive daemon. This must not be the same as INTERRUPT_EVENT. */
-#define SMC91111_TX_WAIT_EVENT RTEMS_EVENT_3 /* event to send when tx buffers become available */
-
-/* Set to perms of:
- 0 disables all debug output
- 1 for process debug output
- 2 for added data IO output: get_reg, put_reg
- 4 for packet allocation/free output
- 8 for only startup status, so we can tell we're installed OK
- 16 dump phy read/write
- 32 precise register dump
- 64 dump packets
-*/
-/*#define DEBUG (-1)*/
-/*#define DEBUG (-1 & ~(16))*/
-#define DEBUG (0)
-/*#define DEBUG (1)*/
-
-#include "smc91111config.h"
-#include <libchip/smc91111.h>
-
-#ifdef BSP_FEATURE_IRQ_EXTENSION
- #include <rtems/irq-extension.h>
-#endif
-
-struct lan91cxx_priv_data smc91111;
-
-int lan91cxx_hardware_init(struct lan91cxx_priv_data *cpd);
-static uint16_t lan91cxx_read_phy(struct lan91cxx_priv_data *cpd,
- uint8_t phyaddr, uint8_t phyreg);
-static void lan91cxx_write_phy(struct lan91cxx_priv_data *cpd,
- uint8_t phyaddr, uint8_t phyreg,
- uint16_t value);
-static void lan91cxx_start(struct ifnet *ifp);
-static void smc91111_start(struct ifnet *ifp);
-static int smc_probe(struct lan91cxx_priv_data *cpd);
-static void smc91111_stop(struct lan91cxx_priv_data *cpd);
-static void smc91111_init(void *arg);
-#ifndef BSP_FEATURE_IRQ_EXTENSION
-static void lan91cxx_finish_sent(struct lan91cxx_priv_data *cpd);
-#endif
-#if 0
-static int lan91cxx_phy_fixed(struct lan91cxx_priv_data *cpd);
-static void lan91cxx_phy_configure(struct lan91cxx_priv_data *cpd);
-#endif
-
-#define min(l,r) ((l) < (r) ? (l) : (r))
-#define max(l,r) ((l) > (r) ? (l) : (r))
-
-#ifndef BSP_FEATURE_IRQ_EXTENSION
-/* \ ------------- Interrupt ------------- \ */
-static void lan91cxx_interrupt_handler(void *arg)
-{
- struct lan91cxx_priv_data *cpd = arg;
- unsigned short irq, event;
- unsigned short oldbase;
- unsigned short oldpointer;
- INCR_STAT(cpd, interrupts);
- DEBUG_FUNCTION();
-
- HAL_READ_UINT16(cpd->base + (LAN91CXX_BS), oldbase);
- oldpointer = get_reg(cpd, LAN91CXX_POINTER);
-
- /* Get the (unmasked) requests */
- irq = get_reg(cpd, LAN91CXX_INTERRUPT);
- event = irq & (irq >> 8) & 0xff;
- if (0 == event)
- return;
-
- /*put_reg(cpd, LAN91CXX_INTERRUPT, irq ); */ /* ack interrupts */
-
- if (event & LAN91CXX_INTERRUPT_ERCV_INT) {
- db_printf("Early receive interrupt");
- } else if (event & LAN91CXX_INTERRUPT_EPH_INT) {
- db_printf("ethernet protocol handler failures");
- } else if (event & LAN91CXX_INTERRUPT_RX_OVRN_INT) {
- db_printf("receive overrun");
- } else if (event & LAN91CXX_INTERRUPT_ALLOC_INT) {
- db_printf("allocation interrupt");
- } else {
-
- if (event & LAN91CXX_INTERRUPT_TX_SET) {
- db_printf("#*tx irq\n");
- lan91cxx_finish_sent(cpd);
- put_reg(cpd, LAN91CXX_INTERRUPT,
- (irq & 0xff00) | LAN91CXX_INTERRUPT_TX_INT);
-
- /*rtems_bsdnet_event_send (cpd->txDaemonTid, SMC91111_INTERRUPT_EVENT); */
- /*put_reg(cpd, LAN91CXX_INTERRUPT, (irq & 0xff00) | LAN91CXX_INTERRUPT_TX_INT); */
- /*rtems_bsdnet_event_send (cpd->txDaemonTid, SMC91111_TX_WAIT_EVENT); */
- }
- if (event & LAN91CXX_INTERRUPT_RCV_INT) {
- db_printf("#*rx irq\n");
- rtems_bsdnet_event_send(cpd->rxDaemonTid,
- SMC91111_INTERRUPT_EVENT);
- }
- if (event &
- ~(LAN91CXX_INTERRUPT_TX_SET | LAN91CXX_INTERRUPT_RCV_INT))
- db_printf("Unknown interrupt\n");
- }
- db_printf("out %s\n", __FUNCTION__);
-
- put_reg(cpd, LAN91CXX_POINTER, oldpointer);
- HAL_WRITE_UINT16(cpd->base + (LAN91CXX_BS), oldbase);
-}
-#endif
-
-/* \ ------------- Rx receive ------------- \ */
-
- /**/
-/* This function is called as a result of the "readpacket()" call.*/
-/* Its job is to actually fetch data for a packet from the hardware once*/
-/* memory buffers have been allocated for the packet. Note that the buffers*/
-/* may come in pieces, using a mbuf list. */
-static void lan91cxx_recv(struct lan91cxx_priv_data *cpd, struct mbuf *m)
-{
- struct ifnet *ifp = &cpd->arpcom.ac_if;
- struct ether_header *eh;
- short mlen = 0, plen;
- char *start;
- rxd_t *data = NULL, val;
-#if DEBUG & 64
- rxd_t lp = 0;
-#else
- /* start is only read with debug enabled */
- (void)start;
-#endif
- struct mbuf *n;
- dbg_prefix = "<";
-
- DEBUG_FUNCTION();
- INCR_STAT(cpd, rx_deliver);
-
- /* ############ read packet ############ */
-
- put_reg(cpd, LAN91CXX_POINTER,
- (LAN91CXX_POINTER_RCV | LAN91CXX_POINTER_READ |
- LAN91CXX_POINTER_AUTO_INCR));
- val = get_data(cpd);
-
- /* packet length (minus header/footer) */
-#ifdef LAN91CXX_32BIT_RX
- val = CYG_LE32_TO_CPU(val);
- plen = (val >> 16) - 6;
-#else
- val = CYG_LE16_TO_CPU(val);
- plen = get_data(cpd);
- plen = CYG_LE16_TO_CPU(plen) - 6;
-#endif
-
- if ( cpd->c111_reva || LAN91CXX_RX_STATUS_IS_ODD(cpd, val) ) /* RevA Odd-bit BUG */
- plen++;
-
- for (n = m; n; n = n->m_next) {
-#ifdef LAN91CXX_32BIT_RX
- if (mlen == 2) {
-#if DEBUG & 64
- db_printf("Appending to last apacket\n");
-#endif
-
- val = get_data(cpd);
- *((unsigned short *)data) = (val >> 16) & 0xffff;
- plen -= 2;
- data = (rxd_t *) n->m_data;
- start = (char *)data;
- mlen = n->m_len;
- if ((data) && (mlen > 1)) {
- *(unsigned short *)data = (val & 0xffff);
- data = (rxd_t *)((unsigned short *)data + 1);
- plen -= 2;
- mlen -= 2;
- }
- } else {
- data = (rxd_t *) n->m_data;
- start = (char *)data;
- mlen = n->m_len;
- }
-#else
- data = (rxd_t *) n->m_data;
- start = (char *)data;
- mlen = n->m_len;
-#endif
-
- db1_printf("<[packet : mlen 0x%x, plen 0x%x]\n", mlen, plen);
-
- if (data) {
- while (mlen >= sizeof(*data)) {
-#ifdef LAN91CXX_32BIT_RX
- val = get_data(cpd);
- *(unsigned short *)data = (val >> 16) & 0xffff;
- data = (rxd_t *)((unsigned short *)data + 1);
- *(unsigned short *)data = (val & 0xffff);
- data = (rxd_t *)((unsigned short *)data + 1);
-#else
- *data++ = get_data(cpd);
-#endif
- mlen -= sizeof(*data);
- plen -= sizeof(*data);
- }
- } else { /* must actively discard ie. read it from the chip anyway. */
- while (mlen >= sizeof(*data)) {
- (void)get_data(cpd);
- mlen -= sizeof(*data);
- plen -= sizeof(*data);
- }
- }
-
-#if DEBUG & 64
- lp = 0;
- while (((int)start) < ((int)data)) {
- unsigned char a = *(start++);
- unsigned char b = *(start++);
- db64_printf("%02x %02x ", a, b);
- lp += 2;
- if (lp >= 16) {
- db64_printf("\n");
- lp = 0;
- }
- }
- db64_printf(" \n");
-#endif
- }
- val = get_data(cpd); /* Read control word (and potential data) unconditionally */
-#ifdef LAN91CXX_32BIT_RX
- if (plen & 2) {
- if (data && (mlen>1) ) {
- *(unsigned short *)data = (val >> 16) & 0xffff;
- data = (rxd_t *)((unsigned short *)data + 1);
- val <<= 16;
- mlen-=2;
- }
- }
- if ( (plen & 1) && data && (mlen>0) )
- *(unsigned char *)data = val >> 24;
-#else
- val = CYG_LE16_TO_CPU(val);
- cp = (unsigned char *)data;
-
- CYG_ASSERT(val & LAN91CXX_CONTROLBYTE_RX, "Controlbyte is not for Rx");
- CYG_ASSERT((1 == mlen) == (0 != LAN91CXX_CONTROLBYTE_IS_ODD(cpd, val)),
- "Controlbyte does not match");
- if (data && (1 == mlen) && LAN91CXX_CONTROLBYTE_IS_ODD(cpd, val)) {
- cval = val & 0x00ff; /* last byte contains data */
- *cp = cval;
- }
-#endif
-
- val = get_reg(cpd, LAN91CXX_FIFO_PORTS);
- if (0x8000 & val) { /* Then the Rx FIFO is empty */
- db4_printf
- ("<+Rx packet NOT freed, stat is %x (expected %x)\n",
- val, cpd->rxpacket);
- } else {
- db4_printf("<+Rx packet freed %x (expected %x)\n",
- 0xff & (val >> 8), cpd->rxpacket);
- }
-
- CYG_ASSERT((0xff & (val >> 8)) == cpd->rxpacket,
- "Unexpected rx packet");
-
- /* ############ free packet ############ */
- /* Free packet */
- put_reg(cpd, LAN91CXX_MMU_COMMAND, LAN91CXX_MMU_remrel_rx_frame);
-
- dbg_prefix = "";
-
- /* Remove the mac header. This is different from the NetBSD stack. */
- eh = mtod(m, struct ether_header *);
- m->m_data += sizeof(struct ether_header);
- m->m_len -= sizeof(struct ether_header);
- m->m_pkthdr.len -= sizeof(struct ether_header);
-
- ether_input(ifp, eh, m);
-
-}
-
-/* allocate mbuf chain */
-static struct mbuf *smc91111_allocmbufchain(int totlen, struct ifnet *ifp)
-{
-
- struct mbuf *m, *m0, *newm;
- int len;
-
- MGETHDR(m0, M_DONTWAIT, MT_DATA);
- if (m0 == 0)
- return (0);
- m0->m_pkthdr.rcvif = ifp;
- m0->m_pkthdr.len = totlen;
- len = MHLEN;
- m = m0;
-
- /* This loop goes through and allocates mbufs for all the data we will be copying in. */
- while (totlen > 0) {
- if (totlen >= MINCLSIZE) {
- MCLGET(m, M_DONTWAIT);
- if ((m->m_flags & M_EXT) == 0)
- goto bad;
- len = MCLBYTES;
- }
-
- if (m == m0) {
- caddr_t newdata = (caddr_t)
- ALIGN(m->m_data +
- sizeof(struct ether_header)) -
- sizeof(struct ether_header);
- len -= newdata - m->m_data;
- m->m_data = newdata;
- }
-
- m->m_len = len = min(totlen, len);
-
- totlen -= len;
- if (totlen > 0) {
- MGET(newm, M_DONTWAIT, MT_DATA);
- if (newm == 0)
- goto bad;
- len = MLEN;
- m = m->m_next = newm;
- }
- }
- return (m0);
-
- bad:
- m_freem(m0);
- return (0);
-}
-
-static int readpacket(struct lan91cxx_priv_data *cpd)
-{
- struct mbuf *m;
- unsigned short stat, complen;
- struct ifnet *ifp = &cpd->arpcom.ac_if;
-#ifdef LAN91CXX_32BIT_RX
- uint32_t val;
-#endif
-
- DEBUG_FUNCTION();
-
- /* ############ read packet nr ############ */
- stat = get_reg(cpd, LAN91CXX_FIFO_PORTS);
- db1_printf("+LAN91CXX_FIFO_PORTS: 0x%04x\n", stat);
-
- if (0x8000 & stat) {
- /* Then the Rx FIFO is empty */
- db4_printf("!RxEvent with empty fifo\n");
- return 0;
- }
-
- INCR_STAT(cpd, rx_count);
-
- db4_printf("+Rx packet allocated %x (previous %x)\n",
- 0xff & (stat >> 8), cpd->rxpacket);
-
- /* There is an Rx Packet ready */
- cpd->rxpacket = 0xff & (stat >> 8);
-
- /* ############ read packet header ############ */
- /* Read status and (word) length */
- put_reg(cpd, LAN91CXX_POINTER,
- (LAN91CXX_POINTER_RCV | LAN91CXX_POINTER_READ |
- LAN91CXX_POINTER_AUTO_INCR | 0x0000));
-#ifdef LAN91CXX_32BIT_RX
- val = get_data(cpd);
- val = CYG_LE32_TO_CPU(val);
- stat = val & 0xffff;
- complen = ((val >> 16) & 0xffff) - 6; /* minus header/footer words */
-#else
- stat = get_data(cpd);
- stat = CYG_LE16_TO_CPU(stat);
- complen = get_data(cpd);
- complen = CYG_LE16_TO_CPU(len) - 6; /* minus header/footer words */
-#endif
-
-#ifdef KEEP_STATISTICS
- if (stat & LAN91CXX_RX_STATUS_ALIGNERR)
- INCR_STAT(cpd, rx_align_errors);
- /*if ( stat & LAN91CXX_RX_STATUS_BCAST ) INCR_STAT( ); */
- if (stat & LAN91CXX_RX_STATUS_BADCRC)
- INCR_STAT(cpd, rx_crc_errors);
- if (stat & LAN91CXX_RX_STATUS_TOOLONG)
- INCR_STAT(cpd, rx_too_long_frames);
- if (stat & LAN91CXX_RX_STATUS_TOOSHORT)
- INCR_STAT(cpd, rx_short_frames);
- /*if ( stat & LAN91CXX_RX_STATUS_MCAST ) INCR_STAT( ); */
-#endif /* KEEP_STATISTICS */
-
- if ((stat & LAN91CXX_RX_STATUS_BAD) == 0) {
- INCR_STAT(cpd, rx_good);
- /* Then it's OK */
-
- if (cpd->c111_reva || LAN91CXX_RX_STATUS_IS_ODD(cpd, stat)) /* RevA Odd-bit BUG */
- complen++;
-
-#if DEBUG & 1
- db_printf("good rx - stat: 0x%04x, len: 0x%04x\n", stat,
- complen);
-#endif
- /* Check for bogusly short packets; can happen in promisc mode: */
- /* Asserted against and checked by upper layer driver. */
- if (complen > sizeof(struct ether_header)) {
- /* then it is acceptable; offer the data to the network stack */
-
- complen = ((complen + 3) & ~3);
-
- m = smc91111_allocmbufchain(complen, ifp);
- {
- struct mbuf *n = m;
- db_printf("mbuf-chain:");
- while (n) {
- db_printf("[%" PRIxPTR ":%x]",
- mtod(n, uintptr_t),
- (unsigned int)(n->m_len));
- n = n->m_next;
- }
- db_printf("\n");
- }
-
- if (m) {
- /* fetch packet data into mbuf chain */
- lan91cxx_recv(cpd, m);
- return 1;
- }
- }
- /*(sc->funs->eth_drv->recv)(sc, len); */
- }
-
- /* Not OK for one reason or another... */
- db1_printf("!bad rx: stat: 0x%04x, len: 0x%04x\n", stat, complen);
-
- /* ############ free packet ############ */
- /* Free packet */
- put_reg(cpd, LAN91CXX_MMU_COMMAND, LAN91CXX_MMU_remrel_rx_frame);
- return 1;
-
-}
-
-static void smc91111_rxDaemon(void *arg)
-{
- struct lan91cxx_priv_data *cpd = arg;
- rtems_event_set events;
- DEBUG_FUNCTION();
-
- for (;;) {
- rtems_bsdnet_event_receive(INTERRUPT_EVENT,
- RTEMS_WAIT | RTEMS_EVENT_ANY,
- RTEMS_NO_TIMEOUT, &events);
-
- /* read until read fifo is empty */
- while (!(get_reg(cpd, LAN91CXX_FIFO_PORTS) & 0x8000)) {
- readpacket(cpd);
- }
- }
-}
-
-/* \ ------------- Tx send ------------- \ */
-
-static void sendpacket(struct ifnet *ifp, struct mbuf *m)
-{
- struct lan91cxx_priv_data *cpd = ifp->if_softc;
- int i, len, plen, tcr, odd;
- struct mbuf *n = m;
- unsigned short *sdata = NULL;
- unsigned short ints, control;
- uint16_t packet, status;
- dbg_prefix = ">";
- DEBUG_FUNCTION();
-
- cpd->txbusy = 1;
-
- /* Worry about the TX engine stopping. */
- tcr = get_reg(cpd, LAN91CXX_TCR);
- if (0 == (LAN91CXX_TCR_TXENA & tcr)) {
- db1_printf("> ENGINE RESTART: tcr %x\n", tcr);
- tcr |= LAN91CXX_TCR_TXENA;
- put_reg(cpd, LAN91CXX_TCR, tcr);
- }
-
- /* ############ packet allocation ############ */
-
- /* Find packet length */
- plen = 0;
- while (n) {
- plen += n->m_len;
- n = n->m_next;
- }
-
- /* Alloc new TX packet */
- do {
- put_reg(cpd, LAN91CXX_MMU_COMMAND,
- LAN91CXX_MMU_alloc_for_tx | ((plen >> 8) & 0x07));
-
- i = 1024 * 1024;
- do {
- status = get_reg(cpd, LAN91CXX_INTERRUPT);
- } while (0 == (status & LAN91CXX_INTERRUPT_ALLOC_INT)
- && (--i > 0));
- if (i)
- packet = get_reg(cpd, LAN91CXX_PNR);
- else
- packet = 0xffff;
- db1_printf(">+allocated packet %04x\n", packet);
-
- packet = packet >> 8;
- if (packet & 0x80) {
- /* Hm.. Isn't this a dead end? */
- db1_printf("Allocation failed! Retrying...\n");
- continue;
- }
- } while (0);
-
- db4_printf(">+Tx packet allocated %x (previous %x)\n",
- packet, cpd->txpacket);
-
- cpd->txpacket = packet;
-
- /* ############ assemble packet data ############ */
-
- /* prepare send */
- put_reg(cpd, LAN91CXX_PNR, packet);
- /* Note: Check FIFO state here before continuing? */
- put_reg(cpd, LAN91CXX_POINTER, LAN91CXX_POINTER_AUTO_INCR | 0x0000);
- /* Pointer is now set, and the proper bank is selected for */
- /* data writes. */
-
- /* Prepare header: */
- put_data(cpd, CYG_CPU_TO_LE16(0)); /* reserve space for status word */
- /* packet length (includes status, byte-count and control shorts) */
- put_data(cpd, CYG_CPU_TO_LE16(0x7FE & (plen + 6))); /* Always even, always < 15xx(dec) */
-
- /* Put data into buffer */
- odd = 0;
- n = m;
- while (n) {
- sdata = (unsigned short *)n->m_data;
- len = n->m_len;
-
- CYG_ASSERT(sdata, "!No sg data pointer here");
-
- /* start on an odd offset?
- * If last byte also (1byte mbuf with different pointer should not occur)
- * let following code handle it
- */
- if ( ((unsigned int)sdata & 1) && (len>1) ){
- put_data8(cpd,*(unsigned char *)sdata);
- sdata = (unsigned short *)((unsigned int)sdata + 1);
- odd = ~odd;
- len--;
- }
-
- /* speed up copying a bit, never copy last word */
- while(len >= 17){
- put_data(cpd, *(sdata));
- put_data(cpd, *(sdata+1));
- put_data(cpd, *(sdata+2));
- put_data(cpd, *(sdata+3));
- put_data(cpd, *(sdata+4));
- put_data(cpd, *(sdata+5));
- put_data(cpd, *(sdata+6));
- put_data(cpd, *(sdata+7));
- sdata += 8;
- len -= 16;
- }
-
- /* copy word wise, skip last word */
- while (len >= 3) {
- put_data(cpd, *sdata++);
- len -= sizeof(*sdata);
- }
-
- /* one or two bytes left to put into fifo */
- if ( len > 1 ){
- /* the last 2bytes */
- if ( !odd || n->m_next ){
- put_data(cpd, *sdata++);
- len -= sizeof(*sdata);
- }else{
- /* write next byte, mark that we are not at an odd offset any more,
- * remaining byte will be written outside while together with control byte.
- */
- put_data8(cpd,*(unsigned char *)sdata);
- sdata = (unsigned short *)((unsigned int)sdata + 1);
- odd = 0;
- len--;
- /*break;*/
- }
- }else if ( (len>0) && (n->m_next) ){
- /* one byte left to write, and more bytes is comming in next mbuf */
- put_data8(cpd,*(unsigned char *)sdata);
- odd = ~odd;
- }
-
- n = n->m_next;
- }
-
- /* Lay down the control short unconditionally at the end. */
- /* (or it might use random memory contents) */
- control = 0;
- if ( len > 0 ){
- if ( !odd ) {
- /* Need to set ODD flag and insert the data */
- unsigned char onebyte = *(unsigned char *)sdata;
- control = onebyte;
- control |= LAN91CXX_CONTROLBYTE_ODD;
- }else{
- put_data8(cpd,*(unsigned char *)sdata);
- }
- }
- control |= LAN91CXX_CONTROLBYTE_CRC; /* Just in case... */
- put_data(cpd, CYG_CPU_TO_LE16(control));
-
- m_freem(m);
- CYG_ASSERT(sdata, "!No sg data pointer outside");
-
- /* ############ start transmit ############ */
-
- /* Ack TX empty int and unmask it. */
- ints = get_reg(cpd, LAN91CXX_INTERRUPT) & 0xff00;
- put_reg(cpd, LAN91CXX_INTERRUPT,
- ints | LAN91CXX_INTERRUPT_TX_EMPTY_INT);
- put_reg(cpd, LAN91CXX_INTERRUPT, ints | LAN91CXX_INTERRUPT_TX_INT_M); /* notify on error only (Autorelease) */
-
- /* Enqueue the packet */
- put_reg(cpd, LAN91CXX_MMU_COMMAND, LAN91CXX_MMU_enq_packet);
-
- ints = get_reg(cpd, LAN91CXX_INTERRUPT);
- db1_printf(">END: ints at TX: %04x\n", ints);
- dbg_prefix = "";
-}
-
-static void smc91111_txDaemon(void *arg)
-{
- struct lan91cxx_priv_data *cpd = arg;
- struct ifnet *ifp = &cpd->arpcom.ac_if;
- struct mbuf *m;
- rtems_event_set events;
- DEBUG_FUNCTION();
-
- for (;;) {
- /*
- * Wait for packet
- */
-
- rtems_bsdnet_event_receive
- (SMC91111_START_TRANSMIT_EVENT,
- RTEMS_EVENT_ANY | RTEMS_WAIT, RTEMS_NO_TIMEOUT, &events);
-
- /*IF_DEQUEUE (&ifp->if_snd, m);
- if (m) {
- sendpacket (ifp, m);
- } */
-
- for (;;) {
- IF_DEQUEUE(&ifp->if_snd, m);
- if (!m)
- break;
- sendpacket(ifp, m);
- }
- ifp->if_flags &= ~IFF_OACTIVE;
-
- }
-
-}
-
-/* start transmit */
-static void smc91111_start(struct ifnet *ifp)
-{
- struct lan91cxx_priv_data *cpd = ifp->if_softc;
-
- if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
- return;
-
- rtems_bsdnet_event_send(cpd->txDaemonTid, START_TRANSMIT_EVENT);
- ifp->if_flags |= IFF_OACTIVE;
-
-}
-
-#ifndef BSP_FEATURE_IRQ_EXTENSION
-/* called after a tx error interrupt, freet the packet */
-static void lan91cxx_finish_sent(struct lan91cxx_priv_data *cpd)
-{
- unsigned short packet, tcr;
- int saved_packet;
-
- DEBUG_FUNCTION();
-
- INCR_STAT(cpd, tx_complete);
-
- saved_packet = get_reg(cpd, LAN91CXX_PNR);
-
- /* Ack and mask TX interrupt set */
- /*ints = get_reg(cpd, LAN91CXX_INTERRUPT) & 0xff00;
- ints |= LAN91CXX_INTERRUPT_TX_SET_ACK;
- ints &= ~LAN91CXX_INTERRUPT_TX_SET_M;
- put_reg(cpd, LAN91CXX_INTERRUPT, ints); */
-
- /* Get number of completed packet and read the status word */
- packet = get_reg(cpd, LAN91CXX_FIFO_PORTS);
- db1_printf("%s:START: fifo %04x \n", __FUNCTION__, packet);
-
- {
- unsigned short reg;
-
- reg = get_reg(cpd, LAN91CXX_EPH_STATUS);
-
- /* Covering each bit in turn... */
- if (reg & LAN91CXX_STATUS_TX_UNRN)
- INCR_STAT(cpd, tx_underrun);
- if (reg & LAN91CXX_STATUS_LOST_CARR)
- INCR_STAT(cpd, tx_carrier_loss);
- if (reg & LAN91CXX_STATUS_LATCOL)
- INCR_STAT(cpd, tx_late_collisions);
- if (reg & LAN91CXX_STATUS_TX_DEFR)
- INCR_STAT(cpd, tx_deferred);
- if (reg & LAN91CXX_STATUS_SQET)
- INCR_STAT(cpd, tx_sqetesterrors);
- if (reg & LAN91CXX_STATUS_16COL)
- INCR_STAT(cpd, tx_max_collisions);
- if (reg & LAN91CXX_STATUS_MUL_COL)
- INCR_STAT(cpd, tx_mult_collisions);
- if (reg & LAN91CXX_STATUS_SNGL_COL)
- INCR_STAT(cpd, tx_single_collisions);
- if (reg & LAN91CXX_STATUS_TX_SUC)
- INCR_STAT(cpd, tx_good);
-
- cpd->stats.tx_total_collisions =
- cpd->stats.tx_late_collisions +
- cpd->stats.tx_max_collisions +
- cpd->stats.tx_mult_collisions +
- cpd->stats.tx_single_collisions;
-
- /* We do not need to look in the Counter Register (LAN91CXX_COUNTER)
- because it just mimics the info we already have above. */
- }
-
- /* We do not really care about Tx failure. Ethernet is not a reliable
- medium. But we do care about the TX engine stopping. */
- tcr = get_reg(cpd, LAN91CXX_TCR);
- if (0 == (LAN91CXX_TCR_TXENA & tcr)) {
- db1_printf("%s: ENGINE RESTART: tcr %x \n", __FUNCTION__, tcr);
- tcr |= LAN91CXX_TCR_TXENA;
- put_reg(cpd, LAN91CXX_TCR, tcr);
- }
-
- packet &= 0xff;
-
- /* and then free the packet */
- put_reg(cpd, LAN91CXX_PNR, cpd->txpacket);
- put_reg(cpd, LAN91CXX_MMU_COMMAND, LAN91CXX_MMU_rel_packet);
-
- while (get_reg(cpd, LAN91CXX_MMU_COMMAND) & LAN91CXX_MMU_COMMAND_BUSY) ;
- /* Don't change Packet Number Reg until busy bit is cleared */
- /* Per LAN91C111 Spec, Page 50 */
- put_reg(cpd, LAN91CXX_PNR, saved_packet);
-
-}
-#endif
-
-/* \ ------------- Helpers ------------- \ */
-
-/*
- * Show interface statistics
- */
-static void smc91111_stats(struct lan91cxx_priv_data *priv)
-{
- printf("tx_good :%-8d\n", priv->stats.tx_good);
- printf("tx_max_collisions :%-8d\n", priv->stats.tx_max_collisions);
- printf("tx_late_collisions :%-8d\n", priv->stats.tx_late_collisions);
- printf("tx_underrun :%-8d\n", priv->stats.tx_underrun);
- printf("tx_carrier_loss :%-8d\n", priv->stats.tx_carrier_loss);
- printf("tx_deferred :%-8d\n", priv->stats.tx_deferred);
- printf("tx_sqetesterrors :%-8d\n", priv->stats.tx_sqetesterrors);
- printf("tx_single_collisions:%-8d\n", priv->stats.tx_single_collisions);
- printf("tx_mult_collisions :%-8d\n", priv->stats.tx_mult_collisions);
- printf("tx_total_collisions :%-8d\n", priv->stats.tx_total_collisions);
- printf("rx_good :%-8d\n", priv->stats.rx_good);
- printf("rx_crc_errors :%-8d\n", priv->stats.rx_crc_errors);
- printf("rx_align_errors :%-8d\n", priv->stats.rx_align_errors);
- printf("rx_resource_errors :%-8d\n", priv->stats.rx_resource_errors);
- printf("rx_overrun_errors :%-8d\n", priv->stats.rx_overrun_errors);
- printf("rx_collisions :%-8d\n", priv->stats.rx_collisions);
- printf("rx_short_frames :%-8d\n", priv->stats.rx_short_frames);
- printf("rx_too_long_frames :%-8d\n", priv->stats.rx_too_long_frames);
- printf("rx_symbol_errors :%-8d\n", priv->stats.rx_symbol_errors);
- printf("interrupts :%-8d\n", priv->stats.interrupts);
- printf("rx_count :%-8d\n", priv->stats.rx_count);
- printf("rx_deliver :%-8d\n", priv->stats.rx_deliver);
- printf("rx_resource :%-8d\n", priv->stats.rx_resource);
- printf("rx_restart :%-8d\n", priv->stats.rx_restart);
- printf("tx_count :%-8d\n", priv->stats.tx_count);
- printf("tx_complete :%-8d\n", priv->stats.tx_complete);
- printf("tx_dropped :%-8d\n", priv->stats.tx_dropped);
-}
-
-/*
- * Driver ioctl handler
- */
-static int smc91111_ioctl(struct ifnet *ifp, ioctl_command_t command, caddr_t data)
-{
- struct lan91cxx_priv_data *cpd = ifp->if_softc;
- int error = 0;
- DEBUG_FUNCTION();
-
- switch (command) {
- case SIOCGIFADDR:
- case SIOCSIFADDR:
- db_printf("SIOCSIFADDR\n");
- ether_ioctl(ifp, command, data);
- break;
-
- case SIOCSIFFLAGS:
- db_printf("SIOCSIFFLAGS\n");
- switch (ifp->if_flags & (IFF_UP | IFF_RUNNING)) {
- case IFF_RUNNING:
- smc91111_stop(cpd);
- break;
-
- case IFF_UP:
- smc91111_init(cpd);
- break;
-
- case IFF_UP | IFF_RUNNING:
- smc91111_stop(cpd);
- smc91111_init(cpd);
- break;
-
- default:
- break;
- }
- break;
-
- case SIO_RTEMS_SHOW_STATS:
- db_printf("SIO_RTEMS_SHOW_STATS\n");
- smc91111_stats(cpd);
- break;
-
- /*
- * FIXME: All sorts of multicast commands need to be added here!
- */
- default:
- error = EINVAL;
- break;
- }
-
- return error;
-}
-
-/*
- * Attach an SMC91111 driver to the system
- */
-int _rtems_smc91111_driver_attach (struct rtems_bsdnet_ifconfig *config,
- struct scmv91111_configuration * chip)
-{
- struct ifnet *ifp;
- struct lan91cxx_priv_data *cpd;
- int unitNumber;
- char *unitName;
- int mtu;
- DEBUG_FUNCTION();
-
- /* parse driver name */
- if ((unitNumber = rtems_bsdnet_parse_driver_name(config, &unitName)) < 0) {
- db_printf("Unitnumber < 0: %d\n", unitNumber);
- return 0;
- }
-
- db_printf("Unitnumber: %d, baseaddr: 0x%p\n", unitNumber, chip->baseaddr);
-
- cpd = &smc91111;
- ifp = &cpd->arpcom.ac_if;
- memset(cpd, 0, sizeof(*cpd));
-
- cpd->config = *chip;
- cpd->base = chip->baseaddr;
-
- if (smc_probe(cpd)) {
- return 0;
- }
-
- if (config->hardware_address) {
- memcpy(cpd->arpcom.ac_enaddr, config->hardware_address, ETHER_ADDR_LEN);
- } else {
-#ifdef SMC91111_ENADDR_IS_SETUP
- /* The address was put in the chip at reset time. Retrieve it. */
- int i;
- for (i = 0; i < sizeof(cpd->enaddr); i += 2) {
- unsigned short r = get_reg(cpd, LAN91CXX_IA01 + i / 2);
- cpd->arpcom.ac_enaddr[i] = r;
- cpd->arpcom.ac_enaddr[i+1] = r >> 8;
- }
-#else
- /* dummy default address */
- cpd->arpcom.ac_enaddr[0] = 0x12;
- cpd->arpcom.ac_enaddr[1] = 0x13;
- cpd->arpcom.ac_enaddr[2] = 0x14;
- cpd->arpcom.ac_enaddr[3] = 0x15;
- cpd->arpcom.ac_enaddr[4] = 0x16;
- cpd->arpcom.ac_enaddr[5] = 0x17;
-#endif
- }
-
- cpd->enaddr[0] = cpd->arpcom.ac_enaddr[0];
- cpd->enaddr[1] = cpd->arpcom.ac_enaddr[1];
- cpd->enaddr[2] = cpd->arpcom.ac_enaddr[2];
- cpd->enaddr[3] = cpd->arpcom.ac_enaddr[3];
- cpd->enaddr[4] = cpd->arpcom.ac_enaddr[4];
- cpd->enaddr[5] = cpd->arpcom.ac_enaddr[5];
- cpd->rpc_cur_mode =
- LAN91CXX_RPCR_LEDA_RX | LAN91CXX_RPCR_LEDB_LINK |
- LAN91CXX_RPCR_ANEG;
-
- if (config->mtu)
- mtu = config->mtu;
- else
- mtu = ETHERMTU;
-
- /*
- * Set up network interface values
- */
- ifp->if_softc = cpd;
- ifp->if_unit = unitNumber;
- ifp->if_name = unitName;
- ifp->if_mtu = mtu;
- ifp->if_init = smc91111_init;
- ifp->if_ioctl = smc91111_ioctl;
- ifp->if_start = smc91111_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);
-
-#if DEBUG
- printf("SMC91111 : driver has been attached\n");
-#endif
-
- return 1;
-};
-
-/* \ ------------- Initialization ------------- \ */
-
-/*
- * Initialize and start the device
- */
-static void smc91111_init(void *arg)
-{
- struct lan91cxx_priv_data *cpd = arg;
- struct ifnet *ifp = &cpd->arpcom.ac_if;
- DEBUG_FUNCTION();
-
- if (cpd->txDaemonTid == 0) {
-
- lan91cxx_hardware_init(cpd);
- lan91cxx_start(ifp);
-
- cpd->rxDaemonTid = rtems_bsdnet_newproc("DCrx", 4096,
- smc91111_rxDaemon, cpd);
- cpd->txDaemonTid =
- rtems_bsdnet_newproc("DCtx", 4096, smc91111_txDaemon, cpd);
- } else {
- lan91cxx_start(ifp);
- }
-
- /*
- * Tell the world that we're running.
- */
- ifp->if_flags |= IFF_RUNNING;
-}
-
-/*
- * Stop the device
- */
-static void smc91111_stop(struct lan91cxx_priv_data *cpd)
-{
- struct ifnet *ifp = &cpd->arpcom.ac_if;
- DEBUG_FUNCTION();
-
- ifp->if_flags &= ~IFF_RUNNING;
-
- /* Reset chip */
- put_reg(cpd, LAN91CXX_RCR, LAN91CXX_RCR_SOFT_RST);
- put_reg(cpd, LAN91CXX_RCR, 0);
- cpd->txbusy = cpd->within_send = 0;
-
-}
-
-int lan91cxx_hardware_init(struct lan91cxx_priv_data *cpd)
-{
- unsigned short val;
- int i;
-
- DEBUG_FUNCTION();
-
- cpd->txbusy = cpd->within_send = 0;
-
- /* install interrupt vector */
-#ifdef BSP_FEATURE_IRQ_EXTENSION
- {
- rtems_status_code sc = RTEMS_SUCCESSFUL;
-
- sc = rtems_interrupt_handler_install(
- cpd->config.vector,
- cpd->config.info,
- cpd->config.options,
- cpd->config.interrupt_wrapper,
- cpd
- );
- if (sc != RTEMS_SUCCESSFUL) {
- printf("rtems_interrupt_handler_install returned %d.\n", sc);
- return 0;
- }
- }
-#else
- {
- int rc;
-
- db_printf("Install lan91cxx isr at vec/irq %" PRIu32 "\n", cpd->config.vector);
- rc = rtems_interrupt_handler_install(cpd->config.vector, "smc91cxx",
- RTEMS_INTERRUPT_SHARED, lan91cxx_interrupt_handler, cpd);
- if (rc != RTEMS_SUCCESSFUL)
- return 0;
- }
-#endif
-
- /* Reset chip */
- put_reg(cpd, LAN91CXX_RCR, LAN91CXX_RCR_SOFT_RST);
- put_reg(cpd, LAN91CXX_RCR, 0);
- HAL_DELAY_US(100000);
- put_reg(cpd, LAN91CXX_CONFIG, 0x9000);
- put_reg(cpd, LAN91CXX_RCR, 0);
- put_reg(cpd, LAN91CXX_TCR, 0);
- put_reg(cpd, LAN91CXX_MMU_COMMAND, LAN91CXX_MMU_reset_mmu);
-
- val = get_reg(cpd, LAN91CXX_EPH_STATUS);
- /* probe chip by reading the signature in BS register */
- val = get_banksel(cpd);
- db9_printf("LAN91CXX - supposed BankReg @ %x = %04x\n",
- (unsigned int)(cpd->base + LAN91CXX_BS), val);
-
- if ((0xff00 & val) != 0x3300) {
- printf("No 91Cxx signature");
- printf("smsc_lan91cxx_init: No 91Cxx signature found\n");
- return 0;
- }
-
- val = get_reg(cpd, LAN91CXX_REVISION);
-
- db9_printf("LAN91CXX - type: %01x, rev: %01x\n",
- (val >> 4) & 0xf, val & 0xf);
-
- /* Set RevA flag for LAN91C111 so we can cope with the odd-bit bug. */
- cpd->c111_reva = (val == 0x3390); /* 90=A, 91=B, 92=C */
-
- /* The controller may provide a function used to set up the ESA */
- if (cpd->config_enaddr)
- (*cpd->config_enaddr) (cpd);
-
- db9_printf("LAN91CXX - status: %04x\n", val);
- /* Use statically configured ESA from the private data */
- db9_printf
- ("LAN91CXX - static ESA: %02x:%02x:%02x:%02x:%02x:%02x\n",
- cpd->enaddr[0], cpd->enaddr[1], cpd->enaddr[2],
- cpd->enaddr[3], cpd->enaddr[4], cpd->enaddr[5]);
- /* Set up hardware address */
- for (i = 0; i < sizeof(cpd->enaddr); i += 2)
- put_reg(cpd, LAN91CXX_IA01 + i / 2,
- cpd->enaddr[i] | (cpd->enaddr[i + 1] << 8));
-
- return 1;
-}
-
-/*
- This function is called to "start up" the interface. It may be called
- multiple times, even when the hardware is already running. It will be
- called whenever something "hardware oriented" changes and should leave
- the hardware ready to send/receive packets.
-*/
-static void lan91cxx_start(struct ifnet *ifp)
-{
- struct lan91cxx_priv_data *cpd = ifp->if_softc;
-
- uint16_t intr;
- uint16_t phy_ctl;
- int delay;
- DEBUG_FUNCTION();
-
- HAL_DELAY_US(100000);
-
- /* 91C111 Errata. Internal PHY comes up disabled. Must enable here. */
- phy_ctl = lan91cxx_read_phy(cpd, 0, LAN91CXX_PHY_CTRL);
- phy_ctl &= ~LAN91CXX_PHY_CTRL_MII_DIS;
- lan91cxx_write_phy(cpd, 0, LAN91CXX_PHY_CTRL, phy_ctl);
-
- /* Start auto-negotiation */
- put_reg(cpd, LAN91CXX_RPCR,
- LAN91CXX_RPCR_LEDA_RX | LAN91CXX_RPCR_LEDB_LINK |
- LAN91CXX_RPCR_ANEG);
- cpd->rpc_cur_mode =
- LAN91CXX_RPCR_LEDA_RX | LAN91CXX_RPCR_LEDB_LINK |
- LAN91CXX_RPCR_ANEG;
-
- /* wait for auto-negotiation to finish. */
- /* give it ~5 seconds before giving up (no cable?) */
- delay = 50;
- while (!(lan91cxx_read_phy(cpd, 0, LAN91CXX_PHY_STAT) & 0x20)) {
- if (--delay <= 0) {
- printf("Timeout autonegotiation\n");
- break;
- }
- HAL_DELAY_US(100000);
- }
-
- put_reg(cpd, LAN91CXX_MMU_COMMAND, LAN91CXX_MMU_reset_mmu);
-
- put_reg(cpd, LAN91CXX_INTERRUPT, 0); /* disable interrupts */
- intr = get_reg(cpd, LAN91CXX_INTERRUPT);
- put_reg(cpd, LAN91CXX_INTERRUPT, intr & /* ack old interrupts */
- (LAN91CXX_INTERRUPT_TX_INT |
- LAN91CXX_INTERRUPT_TX_EMPTY_INT |
- LAN91CXX_INTERRUPT_RX_OVRN_INT | LAN91CXX_INTERRUPT_ERCV_INT));
- put_reg(cpd, LAN91CXX_RCR,
- LAN91CXX_RCR_STRIP_CRC | LAN91CXX_RCR_RXEN |
- LAN91CXX_RCR_ALMUL);
- put_reg(cpd, LAN91CXX_TCR, LAN91CXX_TCR_TXENA | LAN91CXX_TCR_PAD_EN);
- put_reg(cpd, LAN91CXX_CONTROL, LAN91CXX_CONTROL_AUTO_RELEASE); /* */
- put_reg(cpd, LAN91CXX_INTERRUPT, /* enable interrupts */
- LAN91CXX_INTERRUPT_RCV_INT_M);
-
- if ((0
-#ifdef ETH_DRV_FLAGS_PROMISC_MODE
- != (flags & ETH_DRV_FLAGS_PROMISC_MODE)
-#endif
- ) || (ifp->if_flags & IFF_PROMISC)
- ) {
- /* Then we select promiscuous mode. */
- unsigned short rcr;
- rcr = get_reg(cpd, LAN91CXX_RCR);
- rcr |= LAN91CXX_RCR_PRMS;
- put_reg(cpd, LAN91CXX_RCR, rcr);
- }
-}
-
-/* \ ------------- Probe ------------- \ */
-
-static const char *chip_ids[15] = {
- NULL, NULL, NULL,
- /* 3 */ "SMC91C90/91C92",
- /* 4 */ "SMC91C94",
- /* 5 */ "SMC91C95",
- /* 6 */ "SMC91C96",
- /* 7 */ "SMC91C100",
- /* 8 */ "SMC91C100FD",
- /* 9 */ "SMC91C11xFD",
- NULL, NULL,
- NULL, NULL, NULL
-};
-
-static int smc_probe(struct lan91cxx_priv_data *cpd)
-{
- unsigned short bank;
- unsigned short revision_register;
-
- DEBUG_FUNCTION();
-
- /* First, see if the high byte is 0x33 */
- HAL_READ_UINT16(cpd->base + (LAN91CXX_BS), bank);
- bank = CYG_LE16_TO_CPU(bank);
- if ((bank & 0xFF00) != 0x3300) {
- db_printf("<1>Smc probe bank check 1 failed.\n");
- return -ENODEV;
- }
- /* The above MIGHT indicate a device, but I need to write to further
- test this. */
- HAL_WRITE_UINT16(cpd->base + (LAN91CXX_BS), CYG_CPU_TO_LE16(0 >> 3));
- HAL_READ_UINT16(cpd->base + (LAN91CXX_BS), bank);
- bank = CYG_LE16_TO_CPU(bank);
- if ((bank & 0xFF00) != 0x3300) {
- db_printf("<1>Smc probe bank check 2 failed.\n");
- return -ENODEV;
- }
-#if SMC_DEBUG > 3
- {
- unsigned short bank16, bank16_0, bank16_1;
- HAL_READ_UINT16(cpd->base + (LAN91CXX_BS), bank16);
- bank = CYG_LE16_TO_CPU(bank);
- HAL_READ_UINT8(cpd->base + (LAN91CXX_BS), bank16_0);
- HAL_READ_UINT8(cpd->base + (LAN91CXX_BS + 1), bank16_1);
-
- db_printf
- ("smc_probe:Bank read as a 16 bit value:0x%04x\n", bank16);
- db_printf
- ("smc_probe:Bank read as an 8 bit value:0x%02x\n",
- bank16_0);
- db_printf
- ("smc_probe:Bank + 1 read as an 8 bit value:0x%02x\n",
- bank16_1);
- }
-#endif
-
- /* check if the revision register is something that I recognize.
- These might need to be added to later, as future revisions
- could be added. */
- revision_register = get_reg(cpd, LAN91CXX_REVISION);
- if (!chip_ids[(revision_register >> 4) & 0xF]) {
- /* I don't recognize this chip, so... */
- db_printf
- ("smc_probe: IO %" PRIxPTR ": Unrecognized revision register:"
- " %x, Contact author. \n", (uintptr_t)cpd->base,
- revision_register);
-
- return -ENODEV;
- }
- db_printf("LAN91CXX(0x%x) - type: %s, rev: %01x\n",
- revision_register,
- chip_ids[(revision_register >> 4) & 0xF],
- revision_register & 0xf);
-
- /* Set RevA flag for LAN91C111 so we can cope with the odd-bit bug. */
- if (revision_register == 0x3390) {
- db_printf("!Revision A\n");
- }
-
- return 0;
-}
-
-#if 0
-/* \ ------------- PHY read/write ------------- \ */
-/*Sets the PHY to a configuration as determined by the user*/
-static int lan91cxx_phy_fixed(struct lan91cxx_priv_data *cpd)
-{
- int my_fixed_caps;
- int cfg1;
-
- DEBUG_FUNCTION();
- db4_printf("lan91cxx_phy_fixed: full duplex: %d, speed: %d\n",
- cpd->config.ctl_rfduplx, cpd->config.ctl_rspeed);
-
- /* Enter Link Disable state */
- cfg1 = lan91cxx_read_phy(cpd, 0, LAN91CXX_PHY_CONFIG1);
- cfg1 |= PHY_CFG1_LNKDIS;
- lan91cxx_write_phy(cpd, 0, LAN91CXX_PHY_CONFIG1, cfg1);
-
- /* Set our fixed capabilities, Disable auto-negotiation */
- my_fixed_caps = 0;
-
- if (cpd->config.ctl_rfduplx)
- my_fixed_caps |= LAN91CXX_PHY_CTRL_DPLX;
-
- if (cpd->config.ctl_rspeed == 100)
- my_fixed_caps |= LAN91CXX_PHY_CTRL_SPEED;
-
- /* Write capabilities to the phy control register */
- lan91cxx_write_phy(cpd, 0, LAN91CXX_PHY_CTRL, my_fixed_caps);
-
- /* Re-Configure the Receive/Phy Control register */
- put_reg(cpd, LAN91CXX_RPCR, cpd->rpc_cur_mode);
-
- return (1);
-}
-#endif
-
-#if 0
-/*Configures the specified PHY using Autonegotiation. */
-static void lan91cxx_phy_configure(struct lan91cxx_priv_data *cpd)
-{
-
- unsigned int phyaddr;
- unsigned int my_phy_caps; /* My PHY capabilities */
- unsigned int my_ad_caps; /* My Advertised capabilities */
- unsigned int status = 0;
- int failed = 0, delay;
-
- DEBUG_FUNCTION();
-
- /* Set the blocking flag */
- cpd->autoneg_active = 1;
-
- /* Get the detected phy address */
- phyaddr = cpd->phyaddr;
-
- /* Reset the PHY, setting all other bits to zero */
- lan91cxx_write_phy(cpd, 0, PHY_CNTL_REG, PHY_CNTL_RST);
-
- /* Wait for the reset to complete, or time out */
- delay = 50;
- while (delay--) {
- if (!(lan91cxx_read_phy(cpd, 0, PHY_CNTL_REG)
- & PHY_CNTL_RST)) {
- break;
- }
- HAL_DELAY_US(100000);
- }
-
- if (delay < 1) {
- db_printf("smc91111:!PHY reset timed out\n");
- goto smc_phy_configure_exit;
- }
-
- /* Read PHY Register 18, Status Output */
- cpd->lastPhy18 = lan91cxx_read_phy(cpd, 0, PHY_INT_REG);
-
- /* Enable PHY Interrupts (for register 18) */
- /* Interrupts listed here are disabled */
- lan91cxx_write_phy(cpd, 0, PHY_MASK_REG,
- PHY_INT_LOSSSYNC | PHY_INT_CWRD | PHY_INT_SSD
- | PHY_INT_ESD | PHY_INT_RPOL | PHY_INT_JAB |
- PHY_INT_SPDDET | PHY_INT_DPLXDET);
-
- /* Configure the Receive/Phy Control register */
- put_reg(cpd, LAN91CXX_RPCR, cpd->rpc_cur_mode);
-
- /* Copy our capabilities from PHY_STAT_REG to PHY_AD_REG */
- my_phy_caps = lan91cxx_read_phy(cpd, phyaddr, PHY_STAT_REG);
- my_ad_caps = PHY_AD_CSMA; /* I am CSMA capable */
-
- if (my_phy_caps & PHY_STAT_CAP_T4)
- my_ad_caps |= PHY_AD_T4;
-
- if (my_phy_caps & PHY_STAT_CAP_TXF)
- my_ad_caps |= PHY_AD_TX_FDX;
-
- if (my_phy_caps & PHY_STAT_CAP_TXH)
- my_ad_caps |= PHY_AD_TX_HDX;
-
- if (my_phy_caps & PHY_STAT_CAP_TF)
- my_ad_caps |= PHY_AD_10_FDX;
-
- if (my_phy_caps & PHY_STAT_CAP_TH)
- my_ad_caps |= PHY_AD_10_HDX;
-
- /* Disable capabilities not selected by our user */
- if (cpd->config.ctl_rspeed != 100) {
- my_ad_caps &= ~(PHY_AD_T4 | PHY_AD_TX_FDX | PHY_AD_TX_HDX);
- }
-
- if (!cpd->config.ctl_rfduplx) {
- my_ad_caps &= ~(PHY_AD_TX_FDX | PHY_AD_10_FDX);
- }
-
- /* Update our Auto-Neg Advertisement Register */
- lan91cxx_write_phy(cpd, 0, PHY_AD_REG, my_ad_caps);
-
- db4_printf("smc91111:phy caps=%x\n", my_phy_caps);
- db4_printf("smc91111:phy advertised caps=%x\n", my_ad_caps);
-
- /* If the user requested no auto neg, then go set his request */
- if (!(cpd->config.ctl_autoneg)) {
- lan91cxx_phy_fixed(cpd);
-
- goto smc_phy_configure_exit;
- }
-
- /* Restart auto-negotiation process in order to advertise my caps */
- lan91cxx_write_phy(cpd, 0, PHY_CNTL_REG,
- PHY_CNTL_ANEG_EN | PHY_CNTL_ANEG_RST);
-
- /* wait for auto-negotiation to finish. */
- /* give it ~5 seconds before giving up (no cable?) */
- delay = 50;
- while (!
- ((status =
- lan91cxx_read_phy(cpd, 0, LAN91CXX_PHY_STAT)) & 0x20)) {
- if (--delay <= 0) {
- printf("Timeout autonegotiation\n");
- failed = 1;
- break;
- }
-
- /* Restart auto-negotiation if remote fault */
- if (status & PHY_STAT_REM_FLT) {
- db_printf("smc91111:PHY remote fault detected\n");
-
- /* Restart auto-negotiation */
- db_printf("smc91111:PHY restarting auto-negotiation\n");
- lan91cxx_write_phy(cpd, 0, PHY_CNTL_REG,
- PHY_CNTL_ANEG_EN |
- PHY_CNTL_ANEG_RST |
- PHY_CNTL_SPEED | PHY_CNTL_DPLX);
- }
- HAL_DELAY_US(100000);
- }
-
- /* Fail if we detected an auto-negotiate remote fault */
- if (status & PHY_STAT_REM_FLT) {
- db_printf("smc91111:PHY remote fault detected\n");
- failed = 1;
- }
-
- /* The smc_phy_interrupt() routine will be called to update lastPhy18 */
-
- /* Set our sysctl parameters to match auto-negotiation results */
- if (cpd->lastPhy18 & PHY_INT_SPDDET) {
- db_printf("smc91111:PHY 100BaseT\n");
- cpd->rpc_cur_mode |= LAN91CXX_RPCR_SPEED;
- } else {
- db_printf("smc91111:PHY 10BaseT\n");
- cpd->rpc_cur_mode &= ~LAN91CXX_RPCR_SPEED;
- }
-
- if (cpd->lastPhy18 & PHY_INT_DPLXDET) {
- db_printf("smc91111:PHY Full Duplex\n");
- cpd->rpc_cur_mode |= LAN91CXX_RPCR_DPLX;
- } else {
- db_printf("smc91111:PHY Half Duplex\n");
- cpd->rpc_cur_mode &= ~LAN91CXX_RPCR_DPLX;
- }
-
- /* Re-Configure the Receive/Phy Control register */
- put_reg(cpd, LAN91CXX_RPCR, cpd->rpc_cur_mode);
-
- smc_phy_configure_exit:
-
- /* Exit auto-negotiation */
- cpd->autoneg_active = 0;
-}
-#endif
-
-static uint16_t
-lan91cxx_read_phy(struct lan91cxx_priv_data *cpd, uint8_t phyaddr,
- uint8_t phyreg)
-{
- int i, mask, input_idx, clk_idx = 0;
- uint16_t mii_reg, value;
- uint8_t bits[64];
-
- /* 32 consecutive ones on MDO to establish sync */
- for (i = 0; i < 32; ++i)
- bits[clk_idx++] = LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;
-
- /* Start code <01> */
- bits[clk_idx++] = LAN91CXX_MGMT_MDOE;
- bits[clk_idx++] = LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;
-
- /* Read command <10> */
- bits[clk_idx++] = LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;
- bits[clk_idx++] = LAN91CXX_MGMT_MDOE;
-
- /* Output the PHY address, msb first */
- for (mask = 0x10; mask; mask >>= 1) {
- if (phyaddr & mask)
- bits[clk_idx++] =
- LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;
- else
- bits[clk_idx++] = LAN91CXX_MGMT_MDOE;
- }
-
- /* Output the phy register number, msb first */
- for (mask = 0x10; mask; mask >>= 1) {
- if (phyreg & mask)
- bits[clk_idx++] =
- LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;
- else
- bits[clk_idx++] = LAN91CXX_MGMT_MDOE;
- }
-
- /* Tristate and turnaround (1 bit times) */
- bits[clk_idx++] = 0;
-
- /* Input starts at this bit time */
- input_idx = clk_idx;
-
- /* Will input 16 bits */
- for (i = 0; i < 16; ++i)
- bits[clk_idx++] = 0;
-
- /* Final clock bit */
- bits[clk_idx++] = 0;
-
- /* Get the current MII register value */
- mii_reg = get_reg(cpd, LAN91CXX_MGMT);
-
- /* Turn off all MII Interface bits */
- mii_reg &= ~(LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MCLK |
- LAN91CXX_MGMT_MDI | LAN91CXX_MGMT_MDO);
- HAL_DELAY_US(50);
-
- /* Clock all 64 cycles */
- for (i = 0; i < sizeof(bits); ++i) {
- /* Clock Low - output data */
- put_reg(cpd, LAN91CXX_MGMT, mii_reg | bits[i]);
- HAL_DELAY_US(50);
-
- /* Clock Hi - input data */
- put_reg(cpd, LAN91CXX_MGMT,
- mii_reg | bits[i] | LAN91CXX_MGMT_MCLK);
- HAL_DELAY_US(50);
-
- bits[i] |= get_reg(cpd, LAN91CXX_MGMT) & LAN91CXX_MGMT_MDI;
- }
-
- /* Return to idle state */
- put_reg(cpd, LAN91CXX_MGMT, mii_reg);
- HAL_DELAY_US(50);
-
- /* Recover input data */
- for (value = 0, i = 0; i < 16; ++i) {
- value <<= 1;
- if (bits[input_idx++] & LAN91CXX_MGMT_MDI)
- value |= 1;
- }
-
- db16_printf("phy_read : %d : %04x\n", phyreg, value);
- return value;
-}
-
-static void
-lan91cxx_write_phy(struct lan91cxx_priv_data *cpd, uint8_t phyaddr,
- uint8_t phyreg, uint16_t value)
-{
- int i, mask, clk_idx = 0;
- uint16_t mii_reg;
- uint8_t bits[65];
-
- /* 32 consecutive ones on MDO to establish sync */
- for (i = 0; i < 32; ++i)
- bits[clk_idx++] = LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;
-
- /* Start code <01> */
- bits[clk_idx++] = LAN91CXX_MGMT_MDOE;
- bits[clk_idx++] = LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;
-
- /* Write command <01> */
- bits[clk_idx++] = LAN91CXX_MGMT_MDOE;
- bits[clk_idx++] = LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;
-
- /* Output the PHY address, msb first */
- for (mask = 0x10; mask; mask >>= 1) {
- if (phyaddr & mask)
- bits[clk_idx++] =
- LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;
- else
- bits[clk_idx++] = LAN91CXX_MGMT_MDOE;
- }
-
- /* Output the phy register number, msb first */
- for (mask = 0x10; mask; mask >>= 1) {
- if (phyreg & mask)
- bits[clk_idx++] =
- LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;
- else
- bits[clk_idx++] = LAN91CXX_MGMT_MDOE;
- }
-
- /* Tristate and turnaround (2 bit times) */
- bits[clk_idx++] = 0;
- bits[clk_idx++] = 0;
-
- /* Write out 16 bits of data, msb first */
- for (mask = 0x8000; mask; mask >>= 1) {
- if (value & mask)
- bits[clk_idx++] =
- LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;
- else
- bits[clk_idx++] = LAN91CXX_MGMT_MDOE;
- }
-
- /* Final clock bit (tristate) */
- bits[clk_idx++] = 0;
-
- /* Get the current MII register value */
- mii_reg = get_reg(cpd, LAN91CXX_MGMT);
-
- /* Turn off all MII Interface bits */
- mii_reg &= ~(LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MCLK |
- LAN91CXX_MGMT_MDI | LAN91CXX_MGMT_MDO);
- HAL_DELAY_US(50);
-
- /* Clock all cycles */
- for (i = 0; i < sizeof(bits); ++i) {
- /* Clock Low - output data */
- put_reg(cpd, LAN91CXX_MGMT, mii_reg | bits[i]);
- HAL_DELAY_US(50);
-
- /* Clock Hi - input data */
- put_reg(cpd, LAN91CXX_MGMT,
- mii_reg | bits[i] | LAN91CXX_MGMT_MCLK);
- HAL_DELAY_US(50);
-
-/* bits[i] |= get_reg(cpd, LAN91CXX_MGMT) & LAN91CXX_MGMT_MDI;*/
- }
-
- /* Return to idle state */
- put_reg(cpd, LAN91CXX_MGMT, mii_reg);
- HAL_DELAY_US(50);
-
- db16_printf("phy_write: %d : %04x\n", phyreg, value);
-}
-
-#if 0
-void lan91cxx_print_bank(int bank){
- struct lan91cxx_priv_data *cpd = &smc91111;
- int regno;
- unsigned short regval[8];
- int i;
-
- if ( bank >= 4 )
- return;
- for(i=0; i<8; i++){
- regno=i+bank<<3;
- regval[i] = get_reg(cpd, regno);
- }
- printk("---- BANK %d ----\n\r",bank);
- for(i=0; i<8; i++){
- printk("0x%x: 0x%x\n\r",i,regval[i]);
- }
-
-}
-#endif
-
-#endif