source: rtems/c/src/libchip/network/smc91111.c @ 6279149

4.115
Last change on this file since 6279149 was 5130248e, checked in by Daniel Cederman <cederman@…>, on 03/13/14 at 13:28:46

smc91111: Move driver attach prototype to header file.

Also signal to compiler that the start variable in lan91cxx_recv is only used when debugging.

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