source: rtems/c/src/libchip/network/smc91111.c @ 3ffa814

Last change on this file since 3ffa814 was 3ffa814, checked in by Joel Sherrill <joel.sherrill@…>, on 10/05/05 at 19:29:23

2005-10-05 Jiri Gaisler <jiri@…>

Edvin Catovic <edvin@…>
Konrad Eisele <konrad@…>

PR 827/bsps

  • network/Makefile.am, network/open_eth.c, network/open_eth.h: Portion of large update of SPARC BSPs. Includes addition of sis, leon2 and leon3 BSPs, deletion of leon BSP, addition of SMC91111 NIC driver and much more.
  • network/README.smc91111, network/smc91111.c, network/smc91111.h, network/smc91111config.h, network/smc91111exp.h: New files.
  • Property mode set to 100644
File size: 41.9 KB
Line 
1/*
2 *  $Id$
3 */
4
5#include <rtems.h>
6
7/*
8 *  This driver currently only supports architectures with the old style
9 *  exception processing.  The following checks try to keep this
10 *  from being compiled on systems which can't support this driver.
11 *
12 *  NOTE: As of 28 September 2005, this has only been tested on the SPARC,
13 *        so that is all it is enabled for.
14 */
15
16#if defined(__sparc__)
17  #define SMC91111_SUPPORTED
18#endif
19
20#if defined(SMC91111_SUPPORTED)
21
22#include <bsp.h>
23
24#include <stdlib.h>
25#include <stdio.h>
26#include <stdarg.h>
27#include <rtems/error.h>
28#include <rtems/rtems_bsdnet.h>
29
30#include <sys/param.h>
31#include <sys/mbuf.h>
32
33#include <sys/socket.h>
34#include <sys/sockio.h>
35#include <net/if.h>
36#include <netinet/in.h>
37#include <netinet/if_ether.h>
38
39#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. */
40#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. */
41#define SMC91111_TX_WAIT_EVENT        RTEMS_EVENT_3     /* event to send when tx buffers become available */
42
43/* Set to perms of:
44   0 disables all debug output
45   1 for process debug output
46   2 for added data IO output: get_reg, put_reg
47   4 for packet allocation/free output
48   8 for only startup status, so we can tell we're installed OK
49   16 dump phy read/write
50   32 precise register dump
51   64 dump packets
52*/
53/*#define DEBUG (-1)*/
54/*#define DEBUG (-1 & ~(16))*/
55#define DEBUG (0)
56
57#include "smc91111config.h"
58#include <libchip/smc91111.h>
59
60struct lan91cxx_priv_data smc91111;
61
62int lan91cxx_hardware_init(struct lan91cxx_priv_data *cpd);
63static cyg_uint16 lan91cxx_read_phy(struct lan91cxx_priv_data *cpd,
64                                    cyg_uint8 phyaddr, cyg_uint8 phyreg);
65static void lan91cxx_write_phy(struct lan91cxx_priv_data *cpd,
66                               cyg_uint8 phyaddr, cyg_uint8 phyreg,
67                               cyg_uint16 value);
68static void lan91cxx_start(struct ifnet *ifp);
69static void smc91111_start(struct ifnet *ifp);
70static int smc_probe(struct lan91cxx_priv_data *cpd);
71static void smc91111_stop(struct lan91cxx_priv_data *cpd);
72static void smc91111_init(void *arg);
73static void lan91cxx_finish_sent(struct lan91cxx_priv_data *cpd);
74#if 0
75static int lan91cxx_phy_fixed(struct lan91cxx_priv_data *cpd);
76static void lan91cxx_phy_configure(struct lan91cxx_priv_data *cpd);
77#endif
78
79#define min(l,r) ((l) < (r) ? (l) : (r))
80#define max(l,r) ((l) > (r) ? (l) : (r))
81
82/* \ ------------- Interrupt ------------- \ */
83rtems_isr lan91cxx_interrupt_handler(rtems_vector_number v)
84{
85        struct lan91cxx_priv_data *cpd = &smc91111;
86        unsigned short irq, event;
87        unsigned short oldbase;
88        unsigned short oldpointer;
89        INCR_STAT(cpd, interrupts);
90        DEBUG_FUNCTION();
91
92        HAL_READ_UINT16(cpd->base + (LAN91CXX_BS), oldbase);
93        oldpointer = get_reg(cpd, LAN91CXX_POINTER);
94
95        /* Get the (unmasked) requests */
96        irq = get_reg(cpd, LAN91CXX_INTERRUPT);
97        event = irq & (irq >> 8) & 0xff;
98        if (0 == event)
99                return;
100
101        /*put_reg(cpd, LAN91CXX_INTERRUPT, irq ); *//* ack interrupts */
102
103        if (event & LAN91CXX_INTERRUPT_ERCV_INT) {
104                db_printf("Early receive interrupt");
105        } else if (event & LAN91CXX_INTERRUPT_EPH_INT) {
106                db_printf("ethernet protocol handler failures");
107        } else if (event & LAN91CXX_INTERRUPT_RX_OVRN_INT) {
108                db_printf("receive overrun");
109        } else if (event & LAN91CXX_INTERRUPT_ALLOC_INT) {
110                db_printf("allocation interrupt");
111        } else {
112
113                if (event & LAN91CXX_INTERRUPT_TX_SET) {
114                        DEBUG_puts("#tx error\n");
115                        db_printf("#*tx irq\n");
116                        lan91cxx_finish_sent(cpd);
117                        put_reg(cpd, LAN91CXX_INTERRUPT,
118                                (irq & 0xff00) | LAN91CXX_INTERRUPT_TX_INT);
119
120                        /*rtems_event_send (cpd->txDaemonTid, SMC91111_INTERRUPT_EVENT); */
121                        /*put_reg(cpd, LAN91CXX_INTERRUPT, (irq & 0xff00) | LAN91CXX_INTERRUPT_TX_INT); */
122                        /*rtems_event_send (cpd->txDaemonTid, SMC91111_TX_WAIT_EVENT); */
123                }
124                if (event & LAN91CXX_INTERRUPT_RCV_INT) {
125                        db_printf("#*rx irq\n");
126                        rtems_event_send(cpd->rxDaemonTid,
127                                         SMC91111_INTERRUPT_EVENT);
128                }
129                if (event &
130                    ~(LAN91CXX_INTERRUPT_TX_SET | LAN91CXX_INTERRUPT_RCV_INT))
131                        db_printf("Unknown interrupt\n");
132        }
133        db_printf("out %s\n", __FUNCTION__);
134
135        put_reg(cpd, LAN91CXX_POINTER, oldpointer);
136        HAL_WRITE_UINT16(cpd->base + (LAN91CXX_BS), oldbase);
137}
138
139/* \ ------------- Rx receive ------------- \ */
140
141 /**/
142/* This function is called as a result of the "readpacket()" call.*/
143/* Its job is to actually fetch data for a packet from the hardware once*/
144/* memory buffers have been allocated for the packet.  Note that the buffers*/
145/* may come in pieces, using a mbuf list.  */
146static void lan91cxx_recv(struct lan91cxx_priv_data *cpd, struct mbuf *m)
147{
148        struct ifnet *ifp = &cpd->arpcom.ac_if;
149        struct ether_header *eh;
150        short mlen = 0, plen;
151        char *start;
152        rxd_t *data = NULL, val, lp;
153        struct mbuf *n;
154        lp = 0;
155        dbg_prefix = "<";
156
157        DEBUG_FUNCTION();
158        INCR_STAT(cpd, rx_deliver);
159
160        /* ############ read packet ############ */
161
162        put_reg(cpd, LAN91CXX_POINTER,
163                (LAN91CXX_POINTER_RCV | LAN91CXX_POINTER_READ |
164                 LAN91CXX_POINTER_AUTO_INCR));
165        val = get_data(cpd);
166
167        /* packet length (minus header/footer) */
168#ifdef LAN91CXX_32BIT_RX
169        val = CYG_LE32_TO_CPU(val);
170        plen = (val >> 16) - 6;
171#else
172        val = CYG_LE16_TO_CPU(val);
173        plen = get_data(cpd);
174        plen = CYG_LE16_TO_CPU(plen) - 6;
175#endif
176
177        if (LAN91CXX_RX_STATUS_IS_ODD(cpd, val))
178                plen++;
179
180        for (n = m; n; n = n->m_next) {
181#ifdef LAN91CXX_32BIT_RX
182                if (mlen == 2) {
183#if DEBUG & 64
184                        db_printf("Appending to last apacket\n");
185#endif
186
187                        val = get_data(cpd);
188                        *((unsigned short *)data) = (val >> 16) & 0xffff;
189                        plen -= 2;
190                        data = (rxd_t *) n->m_data;
191                        start = (char *)data;
192                        mlen = n->m_len;
193                        if ((data) && (mlen > 1)) {
194                                *((unsigned short *)data)++ = (val & 0xffff);
195                                plen -= 2;
196                                mlen -= 2;
197                        }
198                } else {
199                        data = (rxd_t *) n->m_data;
200                        start = (char *)data;
201                        mlen = n->m_len;
202                }
203#else
204                data = (rxd_t *) n->m_data;
205                start = (char *)data;
206                mlen = n->m_len;
207#endif
208
209                db1_printf("<[packet : mlen 0x%x, plen 0x%x]\n", mlen, plen);
210
211                if (data) {
212                        while (mlen >= sizeof(*data)) {
213#ifdef LAN91CXX_32BIT_RX
214                                val = get_data(cpd);
215                                *((unsigned short *)data)++ =
216                                    (val >> 16) & 0xffff;
217                                *((unsigned short *)data)++ = (val & 0xffff);
218#else
219                                *data++ = get_data(cpd);
220#endif
221                                mlen -= sizeof(*data);
222                                plen -= sizeof(*data);
223                        }
224                } else {        /* must actively discard ie. read it from the chip anyway. */
225                        while (mlen >= sizeof(*data)) {
226                                (void)get_data(cpd);
227                                mlen -= sizeof(*data);
228                                plen -= sizeof(*data);
229                        }
230                }
231
232#if DEBUG & 64
233                lp = 0;
234                while (((int)start) < ((int)data)) {
235                        unsigned char a = *(start++);
236                        unsigned char b = *(start++);
237                        db64_printf("%02x %02x ", a, b);
238                        lp += 2;
239                        if (lp >= 16) {
240                                db64_printf("\n");
241                                lp = 0;
242                        }
243                }
244                db64_printf(" \n");
245
246#endif
247        }
248        val = get_data(cpd);    /* Read control word (and potential data) unconditionally */
249#ifdef LAN91CXX_32BIT_RX
250        if (plen & 2) {
251                if (data) {
252                        *((unsigned short *)data)++ = (val >> 16) & 0xffff;
253                        val <<= 16;
254                }
255        }
256        if (plen & 1)
257                *(unsigned char *)data = val >> 24;
258#else
259        val = CYG_LE16_TO_CPU(val);
260        cp = (unsigned char *)data;
261
262        CYG_ASSERT(val & LAN91CXX_CONTROLBYTE_RX, "Controlbyte is not for Rx");
263        CYG_ASSERT((1 == mlen) == (0 != LAN91CXX_CONTROLBYTE_IS_ODD(cpd, val)),
264                   "Controlbyte does not match");
265        if (data && (1 == mlen) && LAN91CXX_CONTROLBYTE_IS_ODD(cpd, val)) {
266                cval = val & 0x00ff;    /* last byte contains data */
267                *cp = cval;
268        }
269#endif
270
271        val = get_reg(cpd, LAN91CXX_FIFO_PORTS);
272        if (0x8000 & val) {     /* Then the Rx FIFO is empty */
273                db4_printf
274                    ("<+Rx packet NOT freed, stat is %x (expected %x)\n",
275                     val, cpd->rxpacket);
276        } else {
277                db4_printf("<+Rx packet freed %x (expected %x)\n",
278                           0xff & (val >> 8), cpd->rxpacket);
279        }
280
281        CYG_ASSERT((0xff & (val >> 8)) == cpd->rxpacket,
282                   "Unexpected rx packet");
283
284        /* ############ free packet ############ */
285        /* Free packet */
286        put_reg(cpd, LAN91CXX_MMU_COMMAND, LAN91CXX_MMU_remrel_rx_frame);
287
288        dbg_prefix = "";
289
290        /* Remove the mac header. This is different from the NetBSD stack. */
291        eh = mtod(m, struct ether_header *);
292        m->m_data += sizeof(struct ether_header);
293        m->m_len -= sizeof(struct ether_header);
294        m->m_pkthdr.len -= sizeof(struct ether_header);
295
296        ether_input(ifp, eh, m);
297
298}
299
300/* allocate mbuf chain */
301static struct mbuf *smc91111_allocmbufchain(int totlen, struct ifnet *ifp)
302{
303
304        struct mbuf *m, *m0, *newm;
305        int len;
306
307        MGETHDR(m0, M_DONTWAIT, MT_DATA);
308        if (m0 == 0)
309                return (0);
310        m0->m_pkthdr.rcvif = ifp;
311        m0->m_pkthdr.len = totlen;
312        len = MHLEN;
313        m = m0;
314
315        /* This loop goes through and allocates mbufs for all the data we will be copying in.  */
316        while (totlen > 0) {
317                if (totlen >= MINCLSIZE) {
318                        MCLGET(m, M_DONTWAIT);
319                        if ((m->m_flags & M_EXT) == 0)
320                                goto bad;
321                        len = MCLBYTES;
322                }
323
324                if (m == m0) {
325                        caddr_t newdata = (caddr_t)
326                            ALIGN(m->m_data +
327                                  sizeof(struct ether_header)) -
328                            sizeof(struct ether_header);
329                        len -= newdata - m->m_data;
330                        m->m_data = newdata;
331                }
332
333                m->m_len = len = min(totlen, len);
334
335                totlen -= len;
336                if (totlen > 0) {
337                        MGET(newm, M_DONTWAIT, MT_DATA);
338                        if (newm == 0)
339                                goto bad;
340                        len = MLEN;
341                        m = m->m_next = newm;
342                }
343        }
344        return (m0);
345
346      bad:
347        m_freem(m0);
348        return (0);
349}
350
351static int readpacket(struct lan91cxx_priv_data *cpd)
352{
353        struct mbuf *m;
354        unsigned short stat, complen;
355        struct ifnet *ifp = &cpd->arpcom.ac_if;
356#ifdef LAN91CXX_32BIT_RX
357        cyg_uint32 val;
358#endif
359
360        DEBUG_FUNCTION();
361
362        /* ############ read packet nr ############ */
363        stat = get_reg(cpd, LAN91CXX_FIFO_PORTS);
364        db1_printf("+LAN91CXX_FIFO_PORTS: 0x%04x\n", stat);
365
366        if (0x8000 & stat) {
367                /* Then the Rx FIFO is empty */
368                db4_printf("!RxEvent with empty fifo\n");
369                return 0;
370        }
371
372        INCR_STAT(cpd, rx_count);
373
374        db4_printf("+Rx packet allocated %x (previous %x)\n",
375                   0xff & (stat >> 8), cpd->rxpacket);
376
377        /* There is an Rx Packet ready */
378        cpd->rxpacket = 0xff & (stat >> 8);
379
380        /* ############ read packet header ############ */
381        /* Read status and (word) length */
382        put_reg(cpd, LAN91CXX_POINTER,
383                (LAN91CXX_POINTER_RCV | LAN91CXX_POINTER_READ |
384                 LAN91CXX_POINTER_AUTO_INCR | 0x0000));
385#ifdef LAN91CXX_32BIT_RX
386        val = get_data(cpd);
387        val = CYG_LE32_TO_CPU(val);
388        stat = val & 0xffff;
389        complen = ((val >> 16) & 0xffff) - 6;   /* minus header/footer words */
390#else
391        stat = get_data(cpd);
392        stat = CYG_LE16_TO_CPU(stat);
393        complen = get_data(cpd);
394        complen = CYG_LE16_TO_CPU(len) - 6;     /* minus header/footer words */
395#endif
396
397#ifdef KEEP_STATISTICS
398        if (stat & LAN91CXX_RX_STATUS_ALIGNERR)
399                INCR_STAT(cpd, rx_align_errors);
400        /*if ( stat & LAN91CXX_RX_STATUS_BCAST    ) INCR_STAT(  ); */
401        if (stat & LAN91CXX_RX_STATUS_BADCRC)
402                INCR_STAT(cpd, rx_crc_errors);
403        if (stat & LAN91CXX_RX_STATUS_TOOLONG)
404                INCR_STAT(cpd, rx_too_long_frames);
405        if (stat & LAN91CXX_RX_STATUS_TOOSHORT)
406                INCR_STAT(cpd, rx_short_frames);
407        /*if ( stat & LAN91CXX_RX_STATUS_MCAST    ) INCR_STAT(  ); */
408#endif                          /* KEEP_STATISTICS */
409
410        if ((stat & LAN91CXX_RX_STATUS_BAD) == 0) {
411                INCR_STAT(cpd, rx_good);
412                /* Then it's OK */
413
414                if (LAN91CXX_RX_STATUS_IS_ODD(cpd, stat))
415                        complen++;
416
417#if DEBUG & 1
418                db_printf("good rx - stat: 0x%04x, len: 0x%04x\n", stat,
419                          complen);
420#endif
421                /* Check for bogusly short packets; can happen in promisc mode: */
422                /* Asserted against and checked by upper layer driver. */
423                if (complen > sizeof(struct ether_header)) {
424                        /* then it is acceptable; offer the data to the network stack */
425
426                        complen = ((complen + 3) & ~3);
427
428                        m = smc91111_allocmbufchain(complen, ifp);
429                        {
430                                struct mbuf *n = m;
431                                db_printf("mbuf-chain:");
432                                while (n) {
433                                        db_printf("[%x:%x]",
434                                                  (unsigned int)(n->
435                                                                 m_data),
436                                                  (unsigned int)(n->m_len));
437                                        n = n->m_next;
438                                }
439                                db_printf("\n");
440                        }
441
442                        if (m) {
443                                /* fetch packet data into mbuf chain */
444                                lan91cxx_recv(cpd, m);
445                                return 1;
446                        }
447                }
448                /*(sc->funs->eth_drv->recv)(sc, len); */
449        }
450
451        /* Not OK for one reason or another... */
452        db1_printf("!bad rx: stat: 0x%04x, len: 0x%04x\n", stat, complen);
453
454        /* ############ free packet ############ */
455        /* Free packet */
456        put_reg(cpd, LAN91CXX_MMU_COMMAND, LAN91CXX_MMU_remrel_rx_frame);
457        return 1;
458
459}
460
461static void smc91111_rxDaemon(void *arg)
462{
463        struct lan91cxx_priv_data *cpd = arg;
464        rtems_event_set events;
465        DEBUG_FUNCTION();
466
467        for (;;) {
468                rtems_bsdnet_event_receive(INTERRUPT_EVENT,
469                                           RTEMS_WAIT | RTEMS_EVENT_ANY,
470                                           RTEMS_NO_TIMEOUT, &events);
471
472                /* read until read fifo is empty */
473                while (!(get_reg(cpd, LAN91CXX_FIFO_PORTS) & 0x8000)) {
474                        readpacket(cpd);
475                }
476        }
477}
478
479/* \ ------------- Tx send ------------- \ */
480
481static void sendpacket(struct ifnet *ifp, struct mbuf *m)
482{
483        struct lan91cxx_priv_data *cpd = ifp->if_softc;
484        int i, len, plen, tcr;
485        struct mbuf *n = m;
486        unsigned short *sdata = NULL;
487        unsigned short ints, control;
488        cyg_uint16 packet, status;
489        dbg_prefix = ">";
490        DEBUG_FUNCTION();
491
492        cpd->txbusy = 1;
493
494        /* Worry about the TX engine stopping. */
495        tcr = get_reg(cpd, LAN91CXX_TCR);
496        if (0 == (LAN91CXX_TCR_TXENA & tcr)) {
497                db1_printf("> ENGINE RESTART: tcr %x\n", tcr);
498                tcr |= LAN91CXX_TCR_TXENA;
499                put_reg(cpd, LAN91CXX_TCR, tcr);
500        }
501
502        /* ############ packet allocation ############ */
503
504        /* Find packet length */
505        plen = 0;
506        while (n) {
507                plen += n->m_len;
508                n = n->m_next;
509        }
510
511        /* Alloc new TX packet */
512        do {
513                put_reg(cpd, LAN91CXX_MMU_COMMAND,
514                        LAN91CXX_MMU_alloc_for_tx | ((plen >> 8) & 0x07));
515
516                i = 1024 * 1024;
517                do {
518                        status = get_reg(cpd, LAN91CXX_INTERRUPT);
519                } while (0 == (status & LAN91CXX_INTERRUPT_ALLOC_INT)
520                         && (--i > 0));
521                if (i)
522                        packet = get_reg(cpd, LAN91CXX_PNR);
523                else
524                        packet = 0xffff;
525                db1_printf(">+allocated packet %04x\n", packet);
526
527                packet = packet >> 8;
528                if (packet & 0x80) {
529                        /* Hm.. Isn't this a dead end? */
530                        db1_printf("Allocation failed! Retrying...\n");
531                        continue;
532                }
533        } while (0);
534
535        db4_printf(">+Tx packet allocated %x (previous %x)\n",
536                   packet, cpd->txpacket);
537
538        cpd->txpacket = packet;
539
540        /* ############ assemble packet data ############ */
541
542        /* prepare send */
543        put_reg(cpd, LAN91CXX_PNR, packet);
544        /* Note: Check FIFO state here before continuing? */
545        put_reg(cpd, LAN91CXX_POINTER, LAN91CXX_POINTER_AUTO_INCR | 0x0000);
546        /* Pointer is now set, and the proper bank is selected for */
547        /* data writes. */
548
549        /* Prepare header: */
550        put_data(cpd, CYG_CPU_TO_LE16(0));      /* reserve space for status word */
551        /* packet length (includes status, byte-count and control shorts) */
552        put_data(cpd, CYG_CPU_TO_LE16(0x7FE & (plen + 6)));     /* Always even, always < 15xx(dec) */
553
554        /* Put data into buffer */
555        n = m;
556        while (n) {
557                sdata = (unsigned short *)n->m_data;
558                len = n->m_len;
559
560                CYG_ASSERT((0 == (len & 1)
561                            || !(n->m_next)), "!odd length");
562                CYG_ASSERT(sdata, "!No sg data pointer here");
563
564                while (len >= sizeof(*sdata)) {
565                        put_data(cpd, *sdata++);
566                        len -= sizeof(*sdata);
567                }
568                n = n->m_next;
569        }
570#if DEBUG & 64
571        n = m;
572        while (n) {
573                int lp = 0;
574                unsigned char *start = (unsigned char *)n->m_data;
575                len = n->m_len;
576                while (len > 0) {
577                        unsigned char a = *(start++);
578                        unsigned char b = *(start++);
579                        db64_printf("%02x %02x ", a, b);
580                        lp += 2;
581                        if (lp >= 16) {
582                                db64_printf("\n");
583                                lp = 0;
584                        }
585                        len -= 2;
586                }
587                n = n->m_next;
588        }
589        db64_printf(" \n");
590#endif
591
592        m_freem(m);
593        CYG_ASSERT(sdata, "!No sg data pointer outside");
594
595        /* Lay down the control short unconditionally at the end. */
596        /* (or it might use random memory contents) */
597        control = 0;
598        if (1 & plen) {
599                /* Need to set ODD flag and insert the data */
600                unsigned char onebyte = *(unsigned char *)sdata;
601                control = onebyte;
602                control |= LAN91CXX_CONTROLBYTE_ODD;
603        }
604        control |= LAN91CXX_CONTROLBYTE_CRC;    /* Just in case... */
605        put_data(cpd, CYG_CPU_TO_LE16(control));
606
607        /* ############ start transmit ############ */
608
609        /* Ack TX empty int and unmask it. */
610        ints = get_reg(cpd, LAN91CXX_INTERRUPT) & 0xff00;
611        put_reg(cpd, LAN91CXX_INTERRUPT,
612                ints | LAN91CXX_INTERRUPT_TX_EMPTY_INT);
613        put_reg(cpd, LAN91CXX_INTERRUPT, ints | LAN91CXX_INTERRUPT_TX_INT_M);   /* notify on error only (Autorelease) */
614
615        /* Enqueue the packet */
616        put_reg(cpd, LAN91CXX_MMU_COMMAND, LAN91CXX_MMU_enq_packet);
617
618        ints = get_reg(cpd, LAN91CXX_INTERRUPT);
619        db1_printf(">END: ints at TX: %04x\n", ints);
620        dbg_prefix = "";
621}
622
623void smc91111_txDaemon(void *arg)
624{
625        struct lan91cxx_priv_data *cpd = arg;
626        struct ifnet *ifp = &cpd->arpcom.ac_if;
627        struct mbuf *m;
628        rtems_event_set events;
629        DEBUG_FUNCTION();
630
631        for (;;) {
632                /*
633                 * Wait for packet
634                 */
635
636                rtems_bsdnet_event_receive
637                    (SMC91111_START_TRANSMIT_EVENT,
638                     RTEMS_EVENT_ANY | RTEMS_WAIT, RTEMS_NO_TIMEOUT, &events);
639
640                /*IF_DEQUEUE (&ifp->if_snd, m);
641                   if (m) {
642                   sendpacket (ifp, m);
643                   } */
644
645                for (;;) {
646                        IF_DEQUEUE(&ifp->if_snd, m);
647                        if (!m)
648                                break;
649                        sendpacket(ifp, m);
650                }
651                ifp->if_flags &= ~IFF_OACTIVE;
652
653        }
654
655}
656
657/* start transmit */
658static void smc91111_start(struct ifnet *ifp)
659{
660        struct lan91cxx_priv_data *cpd = ifp->if_softc;
661
662        if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
663                return;
664
665        rtems_event_send(cpd->txDaemonTid, START_TRANSMIT_EVENT);
666        ifp->if_flags |= IFF_OACTIVE;
667
668}
669
670/* called after a tx error interrupt, freet the packet */
671static void lan91cxx_finish_sent(struct lan91cxx_priv_data *cpd)
672{
673        unsigned short packet, tcr;
674        int success = 1;
675        int saved_packet;
676
677        DEBUG_FUNCTION();
678
679        INCR_STAT(cpd, tx_complete);
680
681        saved_packet = get_reg(cpd, LAN91CXX_PNR);
682
683        /* Ack and mask TX interrupt set */
684        /*ints = get_reg(cpd, LAN91CXX_INTERRUPT) & 0xff00;
685           ints |= LAN91CXX_INTERRUPT_TX_SET_ACK;
686           ints &= ~LAN91CXX_INTERRUPT_TX_SET_M;
687           put_reg(cpd, LAN91CXX_INTERRUPT, ints); */
688
689        /* Get number of completed packet and read the status word */
690        packet = get_reg(cpd, LAN91CXX_FIFO_PORTS);
691        db1_printf("%s:START: fifo %04x \n", __FUNCTION__, packet);
692
693        {
694                unsigned short reg;
695
696                reg = get_reg(cpd, LAN91CXX_EPH_STATUS);
697
698                /* Covering each bit in turn... */
699                if (reg & LAN91CXX_STATUS_TX_UNRN)
700                        INCR_STAT(cpd, tx_underrun);
701                if (reg & LAN91CXX_STATUS_LOST_CARR)
702                        INCR_STAT(cpd, tx_carrier_loss);
703                if (reg & LAN91CXX_STATUS_LATCOL)
704                        INCR_STAT(cpd, tx_late_collisions);
705                if (reg & LAN91CXX_STATUS_TX_DEFR)
706                        INCR_STAT(cpd, tx_deferred);
707                if (reg & LAN91CXX_STATUS_SQET)
708                        INCR_STAT(cpd, tx_sqetesterrors);
709                if (reg & LAN91CXX_STATUS_16COL)
710                        INCR_STAT(cpd, tx_max_collisions);
711                if (reg & LAN91CXX_STATUS_MUL_COL)
712                        INCR_STAT(cpd, tx_mult_collisions);
713                if (reg & LAN91CXX_STATUS_SNGL_COL)
714                        INCR_STAT(cpd, tx_single_collisions);
715                if (reg & LAN91CXX_STATUS_TX_SUC)
716                        INCR_STAT(cpd, tx_good);
717
718                cpd->stats.tx_total_collisions =
719                    cpd->stats.tx_late_collisions +
720                    cpd->stats.tx_max_collisions +
721                    cpd->stats.tx_mult_collisions +
722                    cpd->stats.tx_single_collisions;
723
724                /* We do not need to look in the Counter Register (LAN91CXX_COUNTER)
725                   because it just mimics the info we already have above. */
726        }
727
728        /* We do not really care about Tx failure.  Ethernet is not a reliable
729           medium.  But we do care about the TX engine stopping. */
730        tcr = get_reg(cpd, LAN91CXX_TCR);
731        if (0 == (LAN91CXX_TCR_TXENA & tcr)) {
732                db1_printf("%s: ENGINE RESTART: tcr %x \n", __FUNCTION__, tcr);
733                tcr |= LAN91CXX_TCR_TXENA;
734                put_reg(cpd, LAN91CXX_TCR, tcr);
735                success = 0;    /* And treat this as an error... */
736        }
737
738        packet &= 0xff;
739
740        /* and then free the packet */
741        put_reg(cpd, LAN91CXX_PNR, cpd->txpacket);
742        put_reg(cpd, LAN91CXX_MMU_COMMAND, LAN91CXX_MMU_rel_packet);
743
744        while (get_reg(cpd, LAN91CXX_MMU_COMMAND) & LAN91CXX_MMU_COMMAND_BUSY) ;
745        /* Don't change Packet Number Reg until busy bit is cleared */
746        /* Per LAN91C111 Spec, Page 50 */
747        put_reg(cpd, LAN91CXX_PNR, saved_packet);
748
749}
750
751/* \ ------------- Helpers ------------- \ */
752
753/*
754 * Show interface statistics
755 */
756static void smc91111_stats(struct lan91cxx_priv_data *priv)
757{
758        printf("tx_good             :%-8d", priv->stats.tx_good);
759        printf("tx_max_collisions   :%-8d", priv->stats.tx_max_collisions);
760        printf("tx_late_collisions  :%-8d", priv->stats.tx_late_collisions);
761        printf("tx_underrun         :%-8d", priv->stats.tx_underrun);
762        printf("tx_carrier_loss     :%-8d", priv->stats.tx_carrier_loss);
763        printf("tx_deferred         :%-8d", priv->stats.tx_deferred);
764        printf("tx_sqetesterrors    :%-8d", priv->stats.tx_sqetesterrors);
765        printf("tx_single_collisions:%-8d", priv->stats.tx_single_collisions);
766        printf("tx_mult_collisions  :%-8d", priv->stats.tx_mult_collisions);
767        printf("tx_total_collisions :%-8d", priv->stats.tx_total_collisions);
768        printf("rx_good             :%-8d", priv->stats.rx_good);
769        printf("rx_crc_errors       :%-8d", priv->stats.rx_crc_errors);
770        printf("rx_align_errors     :%-8d", priv->stats.rx_align_errors);
771        printf("rx_resource_errors  :%-8d", priv->stats.rx_resource_errors);
772        printf("rx_overrun_errors   :%-8d", priv->stats.rx_overrun_errors);
773        printf("rx_collisions       :%-8d", priv->stats.rx_collisions);
774        printf("rx_short_frames     :%-8d", priv->stats.rx_short_frames);
775        printf("rx_too_long_frames  :%-8d", priv->stats.rx_too_long_frames);
776        printf("rx_symbol_errors    :%-8d", priv->stats.rx_symbol_errors);
777        printf("interrupts          :%-8d", priv->stats.interrupts);
778        printf("rx_count            :%-8d", priv->stats.rx_count);
779        printf("rx_deliver          :%-8d", priv->stats.rx_deliver);
780        printf("rx_resource         :%-8d", priv->stats.rx_resource);
781        printf("rx_restart          :%-8d", priv->stats.rx_restart);
782        printf("tx_count            :%-8d", priv->stats.tx_count);
783        printf("tx_complete         :%-8d", priv->stats.tx_complete);
784        printf("tx_dropped          :%-8d", priv->stats.tx_dropped);
785}
786
787/*
788 * Driver ioctl handler
789 */
790static int smc91111_ioctl(struct ifnet *ifp, int command, caddr_t data)
791{
792        struct lan91cxx_priv_data *cpd = ifp->if_softc;
793        int error = 0;
794        DEBUG_FUNCTION();
795
796        switch (command) {
797        case SIOCGIFADDR:
798        case SIOCSIFADDR:
799                db_printf("SIOCSIFADDR\n");
800                ether_ioctl(ifp, command, data);
801                break;
802
803        case SIOCSIFFLAGS:
804                db_printf("SIOCSIFFLAGS\n");
805                switch (ifp->if_flags & (IFF_UP | IFF_RUNNING)) {
806                case IFF_RUNNING:
807                        smc91111_stop(cpd);
808                        break;
809
810                case IFF_UP:
811                        smc91111_init(cpd);
812                        break;
813
814                case IFF_UP | IFF_RUNNING:
815                        smc91111_stop(cpd);
816                        smc91111_init(cpd);
817                        break;
818
819                default:
820                        break;
821                }
822                break;
823
824        case SIO_RTEMS_SHOW_STATS:
825                db_printf("SIO_RTEMS_SHOW_STATS\n");
826                smc91111_stats(cpd);
827                break;
828
829                /*
830                 * FIXME: All sorts of multicast commands need to be added here!
831                 */
832        default:
833                error = EINVAL;
834                break;
835        }
836
837        return error;
838}
839
840/*
841 * Attach an SMC91111 driver to the system
842 */
843int _rtems_smc91111_driver_attach (struct rtems_bsdnet_ifconfig *config,
844                                  struct scmv91111_configuration * chip)
845{
846        struct ifnet *ifp;
847        struct lan91cxx_priv_data *cpd;
848        int unitNumber;
849        char *unitName;
850        int mtu;
851        DEBUG_FUNCTION();
852
853/*      /\* activate io area *\/ */
854/*      switch (sparc_leon23_get_psr_version()) { */
855/*      case 0: */
856/*      case 2: */
857/*              db_printf("Activating Leon2 io port\n"); */
858/*              /\*configure pio *\/ */
859/*              *((volatile unsigned int *)0x80000000) |= 0x10f80000; */
860/*              *((volatile unsigned int *)0x800000A8) |= */
861/*                  (0xe0 | chip->vector) << (8 * (chip->pio - 4)); */
862/*              break; */
863/*      default: */
864/*              { */
865/*                      unsigned long irq_pio, irq_mctrl, addr_pio, addr_mctrl; */
866/*                      if ((addr_pio = */
867/*                           amba_find_apbslv_addr(VENDOR_GAISLER, */
868/*                                                 GAISLER_PIOPORT, &irq_pio)) */
869/*                          && (addr_mctrl = */
870/*                              amba_find_apbslv_addr(VENDOR_ESA, */
871/*                                                    ESA_MCTRL, &irq_mctrl))) { */
872/*                              LEON3_IOPORT_Regs_Map *io = */
873/*                                  (LEON3_IOPORT_Regs_Map *) addr_pio; */
874/*                              db_printf */
875/*                                  ("Activating Leon3 io port for smsc_lan91cxx (pio:%x mctrl:%x)\n", */
876/*                                   (unsigned int)addr_pio, */
877/*                                   (unsigned int)addr_mctrl); */
878/*                              *((volatile unsigned int *)addr_mctrl) |= 0x10f80000;   /\*mctrl ctrl 1 *\/ */
879/*                              io->irqmask |= (1 << chip->pio); */
880/*                              io->irqpol |= (1 << chip->pio); */
881/*                              io->irqedge |= (1 << chip->pio); */
882/*                              io->iodir &= ~(1 << chip->pio); */
883/*                      } else { */
884/*                              return 0; */
885/*                      } */
886/*              } */
887/*      } */
888
889        /* parse driver name */
890        if ((unitNumber =
891             rtems_bsdnet_parse_driver_name(config, &unitName)) < 0) {
892                db_printf("Unitnumber < 0: %d\n", unitNumber);
893                return 0;
894        }
895
896        db_printf("Unitnumber: %d, baseaddr: 0x%p\n", unitNumber, chip->baseaddr);
897
898        cpd = &smc91111;
899        ifp = &cpd->arpcom.ac_if;
900        memset(cpd, 0, sizeof(*cpd));
901
902        cpd->config = *chip;
903        cpd->base = chip->baseaddr;
904
905        if (smc_probe(cpd)) {
906                return 0;
907        }
908
909        if (config->hardware_address) {
910                memcpy(cpd->arpcom.ac_enaddr, config->hardware_address,
911                       ETHER_ADDR_LEN);
912        } else {
913                /* dummy default address */
914                cpd->arpcom.ac_enaddr[0] = 0x12;
915                cpd->arpcom.ac_enaddr[1] = 0x13;
916                cpd->arpcom.ac_enaddr[2] = 0x14;
917                cpd->arpcom.ac_enaddr[3] = 0x15;
918                cpd->arpcom.ac_enaddr[4] = 0x16;
919                cpd->arpcom.ac_enaddr[5] = 0x17;
920        }
921
922        cpd->enaddr[0] = cpd->arpcom.ac_enaddr[0];
923        cpd->enaddr[1] = cpd->arpcom.ac_enaddr[1];
924        cpd->enaddr[2] = cpd->arpcom.ac_enaddr[2];
925        cpd->enaddr[3] = cpd->arpcom.ac_enaddr[3];
926        cpd->enaddr[4] = cpd->arpcom.ac_enaddr[4];
927        cpd->enaddr[5] = cpd->arpcom.ac_enaddr[5];
928        cpd->rpc_cur_mode =
929            LAN91CXX_RPCR_LEDA_RX | LAN91CXX_RPCR_LEDB_LINK |
930            LAN91CXX_RPCR_ANEG;
931
932        if (config->mtu)
933                mtu = config->mtu;
934        else
935                mtu = ETHERMTU;
936
937        /*
938         * Set up network interface values
939         */
940        ifp->if_softc = cpd;
941        ifp->if_unit = unitNumber;
942        ifp->if_name = unitName;
943        ifp->if_mtu = mtu;
944        ifp->if_init = smc91111_init;
945        ifp->if_ioctl = smc91111_ioctl;
946        ifp->if_start = smc91111_start;
947        ifp->if_output = ether_output;
948        ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
949        if (ifp->if_snd.ifq_maxlen == 0)
950                ifp->if_snd.ifq_maxlen = ifqmaxlen;
951
952        /*
953         * Attach the interface
954         */
955        if_attach(ifp);
956        ether_ifattach(ifp);
957
958#ifdef DEBUG
959        printf("SMC91111 : driver has been attached\n");
960#endif
961
962        return 1;
963};
964
965/* \ ------------- Initialization ------------- \ */
966
967/*
968 * Initialize and start the device
969 */
970static void smc91111_init(void *arg)
971{
972        struct lan91cxx_priv_data *cpd = arg;
973        struct ifnet *ifp = &cpd->arpcom.ac_if;
974        DEBUG_FUNCTION();
975
976        if (cpd->txDaemonTid == 0) {
977
978                lan91cxx_hardware_init(cpd);
979                lan91cxx_start(ifp);
980
981                cpd->rxDaemonTid = rtems_bsdnet_newproc("DCrx", 4096,
982                                                        smc91111_rxDaemon, cpd);
983                cpd->txDaemonTid =
984                    rtems_bsdnet_newproc("DCtx", 4096, smc91111_txDaemon, cpd);
985        }
986
987        /*
988         * Tell the world that we're running.
989         */
990        ifp->if_flags |= IFF_RUNNING;
991}
992
993/*
994 * Stop the device
995 */
996static void smc91111_stop(struct lan91cxx_priv_data *cpd)
997{
998        struct ifnet *ifp = &cpd->arpcom.ac_if;
999        DEBUG_FUNCTION();
1000
1001        ifp->if_flags &= ~IFF_RUNNING;
1002
1003        /* Reset chip */
1004        put_reg(cpd, LAN91CXX_RCR, LAN91CXX_RCR_SOFT_RST);
1005        put_reg(cpd, LAN91CXX_RCR, 0);
1006        cpd->txbusy = cpd->within_send = 0;
1007
1008}
1009
1010int lan91cxx_hardware_init(struct lan91cxx_priv_data *cpd)
1011{
1012        unsigned short val;
1013        int i;
1014
1015        DEBUG_FUNCTION();
1016
1017        cpd->txbusy = cpd->within_send = 0;
1018
1019        /* install interrupt vector */
1020        db_printf("Install lan91cxx irqvector at %d\n", cpd->config.vector);
1021        set_vector(lan91cxx_interrupt_handler, cpd->config.vector, 1);
1022
1023        /* Reset chip */
1024        put_reg(cpd, LAN91CXX_RCR, LAN91CXX_RCR_SOFT_RST);
1025        put_reg(cpd, LAN91CXX_RCR, 0);
1026        HAL_DELAY_US(100000);
1027        put_reg(cpd, LAN91CXX_CONFIG, 0x9000);
1028        put_reg(cpd, LAN91CXX_RCR, 0);
1029        put_reg(cpd, LAN91CXX_TCR, 0);
1030        put_reg(cpd, LAN91CXX_MMU_COMMAND, LAN91CXX_MMU_reset_mmu);
1031
1032        val = get_reg(cpd, LAN91CXX_EPH_STATUS);
1033        /* probe chip by reading the signature in BS register */
1034        val = get_banksel(cpd);
1035        db9_printf("LAN91CXX - supposed BankReg @ %x = %04x\n",
1036                   (unsigned int)(cpd->base + LAN91CXX_BS), val);
1037
1038        if ((0xff00 & val) != 0x3300) {
1039                printf("No 91Cxx signature");
1040                printf("smsc_lan91cxx_init: No 91Cxx signature found\n");
1041                return 0;
1042        }
1043
1044        val = get_reg(cpd, LAN91CXX_REVISION);
1045
1046        db9_printf("LAN91CXX - type: %01x, rev: %01x\n",
1047                   (val >> 4) & 0xf, val & 0xf);
1048
1049        /* Set RevA flag for LAN91C111 so we can cope with the odd-bit bug. */
1050        cpd->c111_reva = (val == 0x3390);
1051
1052        /* The controller may provide a function used to set up the ESA */
1053        if (cpd->config_enaddr)
1054                (*cpd->config_enaddr) (cpd);
1055
1056        db9_printf("LAN91CXX - status: %04x\n", val);
1057        /* Use statically configured ESA from the private data */
1058        db9_printf
1059            ("LAN91CXX - static ESA: %02x:%02x:%02x:%02x:%02x:%02x\n",
1060             cpd->enaddr[0], cpd->enaddr[1], cpd->enaddr[2],
1061             cpd->enaddr[3], cpd->enaddr[4], cpd->enaddr[5]);
1062        /* Set up hardware address */
1063        for (i = 0; i < sizeof(cpd->enaddr); i += 2)
1064                put_reg(cpd, LAN91CXX_IA01 + i / 2,
1065                        cpd->enaddr[i] | (cpd->enaddr[i + 1] << 8));
1066
1067        return 1;
1068}
1069
1070/*
1071  This function is called to "start up" the interface.  It may be called
1072  multiple times, even when the hardware is already running.  It will be
1073  called whenever something "hardware oriented" changes and should leave
1074  the hardware ready to send/receive packets.
1075*/
1076static void lan91cxx_start(struct ifnet *ifp)
1077{
1078        struct lan91cxx_priv_data *cpd = ifp->if_softc;
1079
1080        cyg_uint16 intr;
1081        cyg_uint16 phy_ctl;
1082        int delay;
1083        DEBUG_FUNCTION();
1084
1085        HAL_DELAY_US(100000);
1086
1087        /* 91C111 Errata. Internal PHY comes up disabled. Must enable here. */
1088        phy_ctl = lan91cxx_read_phy(cpd, 0, LAN91CXX_PHY_CTRL);
1089        phy_ctl &= ~LAN91CXX_PHY_CTRL_MII_DIS;
1090        lan91cxx_write_phy(cpd, 0, LAN91CXX_PHY_CTRL, phy_ctl);
1091
1092        /* Start auto-negotiation */
1093        put_reg(cpd, LAN91CXX_RPCR,
1094                LAN91CXX_RPCR_LEDA_RX | LAN91CXX_RPCR_LEDB_LINK |
1095                LAN91CXX_RPCR_ANEG);
1096        cpd->rpc_cur_mode =
1097            LAN91CXX_RPCR_LEDA_RX | LAN91CXX_RPCR_LEDB_LINK |
1098            LAN91CXX_RPCR_ANEG;
1099
1100        /* wait for auto-negotiation to finish. */
1101        /* give it ~5 seconds before giving up (no cable?) */
1102        delay = 50;
1103        while (!(lan91cxx_read_phy(cpd, 0, LAN91CXX_PHY_STAT) & 0x20)) {
1104                if (--delay <= 0) {
1105                        printf("Timeout autonegotiation\n");
1106                        break;
1107                }
1108                HAL_DELAY_US(100000);
1109        }
1110
1111        put_reg(cpd, LAN91CXX_MMU_COMMAND, LAN91CXX_MMU_reset_mmu);
1112
1113        put_reg(cpd, LAN91CXX_INTERRUPT, 0);    /* disable interrupts */
1114        intr = get_reg(cpd, LAN91CXX_INTERRUPT);
1115        put_reg(cpd, LAN91CXX_INTERRUPT, intr & /* ack old interrupts */
1116                (LAN91CXX_INTERRUPT_TX_INT |
1117                 LAN91CXX_INTERRUPT_TX_EMPTY_INT |
1118                 LAN91CXX_INTERRUPT_RX_OVRN_INT | LAN91CXX_INTERRUPT_ERCV_INT));
1119        put_reg(cpd, LAN91CXX_RCR,
1120                LAN91CXX_RCR_STRIP_CRC | LAN91CXX_RCR_RXEN |
1121                LAN91CXX_RCR_ALMUL);
1122        put_reg(cpd, LAN91CXX_TCR, LAN91CXX_TCR_TXENA | LAN91CXX_TCR_PAD_EN);
1123        put_reg(cpd, LAN91CXX_CONTROL, LAN91CXX_CONTROL_AUTO_RELEASE);  /*  */
1124        put_reg(cpd, LAN91CXX_INTERRUPT,        /* enable interrupts */
1125                LAN91CXX_INTERRUPT_RCV_INT_M);
1126
1127        if ((0
1128#ifdef ETH_DRV_FLAGS_PROMISC_MODE
1129             != (flags & ETH_DRV_FLAGS_PROMISC_MODE)
1130#endif
1131            ) || (ifp->if_flags & IFF_PROMISC)
1132            ) {
1133                /* Then we select promiscuous mode. */
1134                unsigned short rcr;
1135                rcr = get_reg(cpd, LAN91CXX_RCR);
1136                rcr |= LAN91CXX_RCR_PRMS;
1137                put_reg(cpd, LAN91CXX_RCR, rcr);
1138        }
1139}
1140
1141/* \ ------------- Probe ------------- \ */
1142
1143static const char *chip_ids[15] = {
1144        NULL, NULL, NULL,
1145        /* 3 */ "SMC91C90/91C92",
1146        /* 4 */ "SMC91C94",
1147        /* 5 */ "SMC91C95",
1148        /* 6 */ "SMC91C96",
1149        /* 7 */ "SMC91C100",
1150        /* 8 */ "SMC91C100FD",
1151        /* 9 */ "SMC91C11xFD",
1152        NULL, NULL,
1153        NULL, NULL, NULL
1154};
1155
1156static int smc_probe(struct lan91cxx_priv_data *cpd)
1157{
1158        unsigned short bank;
1159        unsigned short revision_register;
1160
1161        DEBUG_FUNCTION();
1162
1163        /* First, see if the high byte is 0x33 */
1164        HAL_READ_UINT16(cpd->base + (LAN91CXX_BS), bank);
1165        bank = CYG_LE16_TO_CPU(bank);
1166        if ((bank & 0xFF00) != 0x3300) {
1167                db_printf("<1>Smc probe bank check 1 failed.\n");
1168                return -ENODEV;
1169        }
1170        /* The above MIGHT indicate a device, but I need to write to further
1171           test this.  */
1172        HAL_WRITE_UINT16(cpd->base + (LAN91CXX_BS), CYG_CPU_TO_LE16(0 >> 3));
1173        HAL_READ_UINT16(cpd->base + (LAN91CXX_BS), bank);
1174        bank = CYG_LE16_TO_CPU(bank);
1175        if ((bank & 0xFF00) != 0x3300) {
1176                db_printf("<1>Smc probe bank check 2 failed.\n");
1177                return -ENODEV;
1178        }
1179#if SMC_DEBUG > 3
1180        {
1181                unsigned short bank16, bank16_0, bank16_1;
1182                HAL_READ_UINT16(cpd->base + (LAN91CXX_BS), bank16);
1183                bank = CYG_LE16_TO_CPU(bank);
1184                HAL_READ_UINT8(cpd->base + (LAN91CXX_BS), bank16_0);
1185                HAL_READ_UINT8(cpd->base + (LAN91CXX_BS + 1), bank16_1);
1186
1187                db_printf
1188                    ("smc_probe:Bank read as a 16 bit value:0x%04x\n", bank16);
1189                db_printf
1190                    ("smc_probe:Bank read as an 8 bit value:0x%02x\n",
1191                     bank16_0);
1192                db_printf
1193                    ("smc_probe:Bank + 1 read as an 8 bit value:0x%02x\n",
1194                     bank16_1);
1195        }
1196#endif
1197
1198        /*  check if the revision register is something that I recognize.
1199           These might need to be added to later, as future revisions
1200           could be added.  */
1201        revision_register = get_reg(cpd, LAN91CXX_REVISION);
1202        if (!chip_ids[(revision_register >> 4) & 0xF]) {
1203                /* I don't recognize this chip, so... */
1204                db_printf
1205                    ("smc_probe: IO %x: Unrecognized revision register:"
1206                     " %x, Contact author. \n", (unsigned int)cpd->base,
1207                     revision_register);
1208
1209                return -ENODEV;
1210        }
1211        db_printf("LAN91CXX(0x%x) - type: %s, rev: %01x\n",
1212                  revision_register,
1213                  chip_ids[(revision_register >> 4) & 0xF],
1214                  revision_register & 0xf);
1215
1216        /* Set RevA flag for LAN91C111 so we can cope with the odd-bit bug. */
1217        if (revision_register == 0x3390) {
1218                db_printf("!Revision A\n");
1219        }
1220
1221        return 0;
1222}
1223
1224#if 0
1225/* \ ------------- PHY read/write ------------- \ */
1226/*Sets the PHY to a configuration as determined by the user*/
1227static int lan91cxx_phy_fixed(struct lan91cxx_priv_data *cpd)
1228{
1229        int my_fixed_caps;
1230        int cfg1;
1231
1232        DEBUG_FUNCTION();
1233        db4_printf("lan91cxx_phy_fixed: full duplex: %d, speed: %d\n",
1234                   cpd->config.ctl_rfduplx, cpd->config.ctl_rspeed);
1235
1236        /* Enter Link Disable state */
1237        cfg1 = lan91cxx_read_phy(cpd, 0, LAN91CXX_PHY_CONFIG1);
1238        cfg1 |= PHY_CFG1_LNKDIS;
1239        lan91cxx_write_phy(cpd, 0, LAN91CXX_PHY_CONFIG1, cfg1);
1240
1241        /* Set our fixed capabilities, Disable auto-negotiation */
1242        my_fixed_caps = 0;
1243
1244        if (cpd->config.ctl_rfduplx)
1245                my_fixed_caps |= LAN91CXX_PHY_CTRL_DPLX;
1246
1247        if (cpd->config.ctl_rspeed == 100)
1248                my_fixed_caps |= LAN91CXX_PHY_CTRL_SPEED;
1249
1250        /* Write capabilities to the phy control register */
1251        lan91cxx_write_phy(cpd, 0, LAN91CXX_PHY_CTRL, my_fixed_caps);
1252
1253        /* Re-Configure the Receive/Phy Control register */
1254        put_reg(cpd, LAN91CXX_RPCR, cpd->rpc_cur_mode);
1255
1256        return (1);
1257}
1258#endif
1259
1260#if 0
1261/*Configures the specified PHY using Autonegotiation. */
1262static void lan91cxx_phy_configure(struct lan91cxx_priv_data *cpd)
1263{
1264
1265        unsigned int phyaddr;
1266        unsigned int my_phy_caps;       /* My PHY capabilities */
1267        unsigned int my_ad_caps;        /* My Advertised capabilities */
1268        unsigned int status = 0;
1269        int failed = 0, delay;
1270
1271        DEBUG_FUNCTION();
1272
1273        /* Set the blocking flag */
1274        cpd->autoneg_active = 1;
1275
1276        /* Get the detected phy address */
1277        phyaddr = cpd->phyaddr;
1278
1279        /* Reset the PHY, setting all other bits to zero */
1280        lan91cxx_write_phy(cpd, 0, PHY_CNTL_REG, PHY_CNTL_RST);
1281
1282        /* Wait for the reset to complete, or time out */
1283        delay = 50;
1284        while (delay--) {
1285                if (!(lan91cxx_read_phy(cpd, 0, PHY_CNTL_REG)
1286                      & PHY_CNTL_RST)) {
1287                        break;
1288                }
1289                HAL_DELAY_US(100000);
1290        }
1291
1292        if (delay < 1) {
1293                db_printf("smc91111:!PHY reset timed out\n");
1294                goto smc_phy_configure_exit;
1295        }
1296
1297        /* Read PHY Register 18, Status Output */
1298        cpd->lastPhy18 = lan91cxx_read_phy(cpd, 0, PHY_INT_REG);
1299
1300        /* Enable PHY Interrupts (for register 18) */
1301        /* Interrupts listed here are disabled */
1302        lan91cxx_write_phy(cpd, 0, PHY_MASK_REG,
1303                           PHY_INT_LOSSSYNC | PHY_INT_CWRD | PHY_INT_SSD
1304                           | PHY_INT_ESD | PHY_INT_RPOL | PHY_INT_JAB |
1305                           PHY_INT_SPDDET | PHY_INT_DPLXDET);
1306
1307        /* Configure the Receive/Phy Control register */
1308        put_reg(cpd, LAN91CXX_RPCR, cpd->rpc_cur_mode);
1309
1310        /* Copy our capabilities from PHY_STAT_REG to PHY_AD_REG */
1311        my_phy_caps = lan91cxx_read_phy(cpd, phyaddr, PHY_STAT_REG);
1312        my_ad_caps = PHY_AD_CSMA;       /* I am CSMA capable */
1313
1314        if (my_phy_caps & PHY_STAT_CAP_T4)
1315                my_ad_caps |= PHY_AD_T4;
1316
1317        if (my_phy_caps & PHY_STAT_CAP_TXF)
1318                my_ad_caps |= PHY_AD_TX_FDX;
1319
1320        if (my_phy_caps & PHY_STAT_CAP_TXH)
1321                my_ad_caps |= PHY_AD_TX_HDX;
1322
1323        if (my_phy_caps & PHY_STAT_CAP_TF)
1324                my_ad_caps |= PHY_AD_10_FDX;
1325
1326        if (my_phy_caps & PHY_STAT_CAP_TH)
1327                my_ad_caps |= PHY_AD_10_HDX;
1328
1329        /* Disable capabilities not selected by our user */
1330        if (cpd->config.ctl_rspeed != 100) {
1331                my_ad_caps &= ~(PHY_AD_T4 | PHY_AD_TX_FDX | PHY_AD_TX_HDX);
1332        }
1333
1334        if (!cpd->config.ctl_rfduplx) {
1335                my_ad_caps &= ~(PHY_AD_TX_FDX | PHY_AD_10_FDX);
1336        }
1337
1338        /* Update our Auto-Neg Advertisement Register */
1339        lan91cxx_write_phy(cpd, 0, PHY_AD_REG, my_ad_caps);
1340
1341        db4_printf("smc91111:phy caps=%x\n", my_phy_caps);
1342        db4_printf("smc91111:phy advertised caps=%x\n", my_ad_caps);
1343
1344        /* If the user requested no auto neg, then go set his request */
1345        if (!(cpd->config.ctl_autoneg)) {
1346                lan91cxx_phy_fixed(cpd);
1347
1348                goto smc_phy_configure_exit;
1349        }
1350
1351        /* Restart auto-negotiation process in order to advertise my caps */
1352        lan91cxx_write_phy(cpd, 0, PHY_CNTL_REG,
1353                           PHY_CNTL_ANEG_EN | PHY_CNTL_ANEG_RST);
1354
1355        /* wait for auto-negotiation to finish. */
1356        /* give it ~5 seconds before giving up (no cable?) */
1357        delay = 50;
1358        while (!
1359               ((status =
1360                 lan91cxx_read_phy(cpd, 0, LAN91CXX_PHY_STAT)) & 0x20)) {
1361                if (--delay <= 0) {
1362                        printf("Timeout autonegotiation\n");
1363                        failed = 1;
1364                        break;
1365                }
1366
1367                /* Restart auto-negotiation if remote fault */
1368                if (status & PHY_STAT_REM_FLT) {
1369                        db_printf("smc91111:PHY remote fault detected\n");
1370
1371                        /* Restart auto-negotiation */
1372                        db_printf("smc91111:PHY restarting auto-negotiation\n");
1373                        lan91cxx_write_phy(cpd, 0, PHY_CNTL_REG,
1374                                           PHY_CNTL_ANEG_EN |
1375                                           PHY_CNTL_ANEG_RST |
1376                                           PHY_CNTL_SPEED | PHY_CNTL_DPLX);
1377                }
1378                HAL_DELAY_US(100000);
1379        }
1380
1381        /* Fail if we detected an auto-negotiate remote fault */
1382        if (status & PHY_STAT_REM_FLT) {
1383                db_printf("smc91111:PHY remote fault detected\n");
1384                failed = 1;
1385        }
1386
1387        /* The smc_phy_interrupt() routine will be called to update lastPhy18 */
1388
1389        /* Set our sysctl parameters to match auto-negotiation results */
1390        if (cpd->lastPhy18 & PHY_INT_SPDDET) {
1391                db_printf("smc91111:PHY 100BaseT\n");
1392                cpd->rpc_cur_mode |= LAN91CXX_RPCR_SPEED;
1393        } else {
1394                db_printf("smc91111:PHY 10BaseT\n");
1395                cpd->rpc_cur_mode &= ~LAN91CXX_RPCR_SPEED;
1396        }
1397
1398        if (cpd->lastPhy18 & PHY_INT_DPLXDET) {
1399                db_printf("smc91111:PHY Full Duplex\n");
1400                cpd->rpc_cur_mode |= LAN91CXX_RPCR_DPLX;
1401        } else {
1402                db_printf("smc91111:PHY Half Duplex\n");
1403                cpd->rpc_cur_mode &= ~LAN91CXX_RPCR_DPLX;
1404        }
1405
1406        /* Re-Configure the Receive/Phy Control register */
1407        put_reg(cpd, LAN91CXX_RPCR, cpd->rpc_cur_mode);
1408
1409      smc_phy_configure_exit:
1410
1411        /* Exit auto-negotiation */
1412        cpd->autoneg_active = 0;
1413}
1414#endif
1415
1416static cyg_uint16
1417lan91cxx_read_phy(struct lan91cxx_priv_data *cpd, cyg_uint8 phyaddr,
1418                  cyg_uint8 phyreg)
1419{
1420        int i, mask, input_idx, clk_idx = 0;
1421        cyg_uint16 mii_reg, value;
1422        cyg_uint8 bits[64];
1423
1424        /* 32 consecutive ones on MDO to establish sync */
1425        for (i = 0; i < 32; ++i)
1426                bits[clk_idx++] = LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;
1427
1428        /* Start code <01> */
1429        bits[clk_idx++] = LAN91CXX_MGMT_MDOE;
1430        bits[clk_idx++] = LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;
1431
1432        /* Read command <10> */
1433        bits[clk_idx++] = LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;
1434        bits[clk_idx++] = LAN91CXX_MGMT_MDOE;
1435
1436        /* Output the PHY address, msb first */
1437        for (mask = 0x10; mask; mask >>= 1) {
1438                if (phyaddr & mask)
1439                        bits[clk_idx++] =
1440                            LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;
1441                else
1442                        bits[clk_idx++] = LAN91CXX_MGMT_MDOE;
1443        }
1444
1445        /* Output the phy register number, msb first */
1446        for (mask = 0x10; mask; mask >>= 1) {
1447                if (phyreg & mask)
1448                        bits[clk_idx++] =
1449                            LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;
1450                else
1451                        bits[clk_idx++] = LAN91CXX_MGMT_MDOE;
1452        }
1453
1454        /* Tristate and turnaround (1 bit times) */
1455        bits[clk_idx++] = 0;
1456
1457        /* Input starts at this bit time */
1458        input_idx = clk_idx;
1459
1460        /* Will input 16 bits */
1461        for (i = 0; i < 16; ++i)
1462                bits[clk_idx++] = 0;
1463
1464        /* Final clock bit */
1465        bits[clk_idx++] = 0;
1466
1467        /* Get the current MII register value */
1468        mii_reg = get_reg(cpd, LAN91CXX_MGMT);
1469
1470        /* Turn off all MII Interface bits */
1471        mii_reg &= ~(LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MCLK |
1472                     LAN91CXX_MGMT_MDI | LAN91CXX_MGMT_MDO);
1473        HAL_DELAY_US(50);
1474
1475        /* Clock all 64 cycles */
1476        for (i = 0; i < sizeof(bits); ++i) {
1477                /* Clock Low - output data */
1478                put_reg(cpd, LAN91CXX_MGMT, mii_reg | bits[i]);
1479                HAL_DELAY_US(50);
1480
1481                /* Clock Hi - input data */
1482                put_reg(cpd, LAN91CXX_MGMT,
1483                        mii_reg | bits[i] | LAN91CXX_MGMT_MCLK);
1484                HAL_DELAY_US(50);
1485
1486                bits[i] |= get_reg(cpd, LAN91CXX_MGMT) & LAN91CXX_MGMT_MDI;
1487        }
1488
1489        /* Return to idle state */
1490        put_reg(cpd, LAN91CXX_MGMT, mii_reg);
1491        HAL_DELAY_US(50);
1492
1493        /* Recover input data */
1494        for (value = 0, i = 0; i < 16; ++i) {
1495                value <<= 1;
1496                if (bits[input_idx++] & LAN91CXX_MGMT_MDI)
1497                        value |= 1;
1498        }
1499
1500        db16_printf("phy_read : %d : %04x\n", phyreg, value);
1501        return value;
1502}
1503
1504static void
1505lan91cxx_write_phy(struct lan91cxx_priv_data *cpd, cyg_uint8 phyaddr,
1506                   cyg_uint8 phyreg, cyg_uint16 value)
1507{
1508        int i, mask, clk_idx = 0;
1509        cyg_uint16 mii_reg;
1510        cyg_uint8 bits[65];
1511
1512        /* 32 consecutive ones on MDO to establish sync */
1513        for (i = 0; i < 32; ++i)
1514                bits[clk_idx++] = LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;
1515
1516        /* Start code <01> */
1517        bits[clk_idx++] = LAN91CXX_MGMT_MDOE;
1518        bits[clk_idx++] = LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;
1519
1520        /* Write command <01> */
1521        bits[clk_idx++] = LAN91CXX_MGMT_MDOE;
1522        bits[clk_idx++] = LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;
1523
1524        /* Output the PHY address, msb first */
1525        for (mask = 0x10; mask; mask >>= 1) {
1526                if (phyaddr & mask)
1527                        bits[clk_idx++] =
1528                            LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;
1529                else
1530                        bits[clk_idx++] = LAN91CXX_MGMT_MDOE;
1531        }
1532
1533        /* Output the phy register number, msb first */
1534        for (mask = 0x10; mask; mask >>= 1) {
1535                if (phyreg & mask)
1536                        bits[clk_idx++] =
1537                            LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;
1538                else
1539                        bits[clk_idx++] = LAN91CXX_MGMT_MDOE;
1540        }
1541
1542        /* Tristate and turnaround (2 bit times) */
1543        bits[clk_idx++] = 0;
1544        bits[clk_idx++] = 0;
1545
1546        /* Write out 16 bits of data, msb first */
1547        for (mask = 0x8000; mask; mask >>= 1) {
1548                if (value & mask)
1549                        bits[clk_idx++] =
1550                            LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;
1551                else
1552                        bits[clk_idx++] = LAN91CXX_MGMT_MDOE;
1553        }
1554
1555        /* Final clock bit (tristate) */
1556        bits[clk_idx++] = 0;
1557
1558        /* Get the current MII register value */
1559        mii_reg = get_reg(cpd, LAN91CXX_MGMT);
1560
1561        /* Turn off all MII Interface bits */
1562        mii_reg &= ~(LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MCLK |
1563                     LAN91CXX_MGMT_MDI | LAN91CXX_MGMT_MDO);
1564        HAL_DELAY_US(50);
1565
1566        /* Clock all cycles */
1567        for (i = 0; i < sizeof(bits); ++i) {
1568                /* Clock Low - output data */
1569                put_reg(cpd, LAN91CXX_MGMT, mii_reg | bits[i]);
1570                HAL_DELAY_US(50);
1571
1572                /* Clock Hi - input data */
1573                put_reg(cpd, LAN91CXX_MGMT,
1574                        mii_reg | bits[i] | LAN91CXX_MGMT_MCLK);
1575                HAL_DELAY_US(50);
1576
1577/*      bits[i] |= get_reg(cpd, LAN91CXX_MGMT) & LAN91CXX_MGMT_MDI;*/
1578        }
1579
1580        /* Return to idle state */
1581        put_reg(cpd, LAN91CXX_MGMT, mii_reg);
1582        HAL_DELAY_US(50);
1583
1584        db16_printf("phy_write: %d : %04x\n", phyreg, value);
1585}
1586
1587#endif
Note: See TracBrowser for help on using the repository browser.