source: rtems/bsps/shared/net/smc91111.c @ a2dad96

5
Last change on this file since a2dad96 was 27de4e1f, checked in by Sebastian Huber <sebastian.huber@…>, on 04/03/18 at 05:20:11

bsps: Move libchip to bsps

This patch is a part of the BSP source reorganization.

Update #3285.

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