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

5
Last change on this file since 3f884b4 was 3f884b4, checked in by Sebastian Huber <sebastian.huber@…>, on 06/13/17 at 09:38:39

bsp: Fixes due to header file changes

Update #2833.

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