00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064 #include <arch/arm.h>
00065
00066 #include <string.h>
00067
00068
00069 #include <sys/atom.h>
00070 #include <sys/heap.h>
00071 #include <sys/thread.h>
00072 #include <sys/event.h>
00073 #include <sys/timer.h>
00074 #include <sys/confnet.h>
00075
00076 #include <dev/irqreg.h>
00077 #include <dev/ax88796.h>
00078 #include "reg_ax88796.h"
00079
00080 #define ASIX_RESET_PIN 10
00081
00082 static NICINFO dcb_eth0;
00083
00088
00089
00095 static IFNET ifn_eth0 = {
00096 IFT_ETHER,
00097 {0, 0, 0, 0, 0, 0},
00098 0,
00099 0,
00100 0,
00101 ETHERMTU,
00102 0,
00103 0,
00104 0,
00105 NutEtherInput,
00106 AsixOutput,
00107 NutEtherOutput
00108 };
00109
00119 NUTDEVICE devAx88796 = {
00120 0,
00121 {'e', 't', 'h', '0', 0, 0, 0, 0, 0},
00122 IFTYP_NET,
00123 0,
00124 0,
00125 &ifn_eth0,
00126 &dcb_eth0,
00127 AsixInit,
00128 0,
00129 0,
00130 0,
00131 0,
00132 0,
00133 0
00134 };
00135
00139 struct nic_pkt_header {
00140 u_char ph_status;
00141 u_char ph_nextpg;
00142 u_short ph_size;
00143 };
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154 void Delay16Cycles(void)
00155 {
00156 _NOP();
00157 _NOP();
00158 _NOP();
00159 _NOP();
00160 _NOP();
00161 _NOP();
00162 _NOP();
00163 _NOP();
00164 _NOP();
00165 _NOP();
00166 _NOP();
00167 _NOP();
00168 _NOP();
00169 _NOP();
00170 _NOP();
00171 _NOP();
00172 }
00173
00174
00180 static u_short MIIPutGet(u_short data, u_char bitCount)
00181 {
00182 u_short rc = 0;
00183 u_short mask;
00184 u_char i;
00185
00186 mask = 1 << (bitCount - 1);
00187
00188 for (i = 0; i < bitCount; i++) {
00189
00190
00191 if (data & mask) {
00192 Asix_Write(MII_EEP, (Asix_Read(MII_EEP) | MII_EEP_MDO));
00193 } else {
00194 Asix_Write(MII_EEP, (Asix_Read(MII_EEP) & ~(MII_EEP_MDO)));
00195 }
00196
00197 Asix_Write(MII_EEP, (Asix_Read(MII_EEP) | MII_EEP_MDC));
00198 Delay16Cycles();
00199
00200 data <<= 1;
00201 rc <<= 1;
00202 rc |= (Asix_Read(MII_EEP) & MII_EEP_MDI) != 0;
00203 Asix_Write(MII_EEP, (Asix_Read(MII_EEP) & ~(MII_EEP_MDC)));
00204 }
00205 return rc;
00206 }
00207
00208
00215 u_short NicPhyRead(u_char reg)
00216 {
00217 u_short rc = 0;
00218
00219
00220 Asix_Write(CR, (Asix_Read(CR) & ~(CR_PS0)));
00221
00222
00223 MIIPutGet(0xFFFF, 16);
00224 MIIPutGet(0xFFFF, 16);
00225
00226
00227 MIIPutGet(0xD0, 9);
00228
00229
00230 MIIPutGet(reg, 5);
00231
00232
00233 MIIPutGet(0x0, 1);
00234
00235
00236 rc = MIIPutGet(0, 16);
00237
00238 return rc;
00239 }
00240
00241
00250 void NicPhyWrite(u_char reg, u_short val)
00251 {
00252
00253
00254 Asix_Write(CR, (Asix_Read(CR) & ~(CR_PS0)));
00255
00256
00257 MIIPutGet(0xFFFF, 16);
00258 MIIPutGet(0xFFFF, 16);
00259
00260
00261 MIIPutGet(0xB0, 9);
00262
00263
00264 MIIPutGet(reg, 5);
00265
00266
00267 MIIPutGet(0x02, 2);
00268
00269
00270 MIIPutGet(val, 16);
00271 }
00272
00273
00274
00278 static void NicCompleteDma(void)
00279 {
00280 u_char i;
00281
00282
00283 do {
00284 i = Asix_Read(PG0_ISR);
00285 } while ((i & ISR_RDC) == 0);
00286
00287
00288 Asix_Write(CR, CR_START | CR_RD2);
00289
00290
00291 Asix_Write(PG0_ISR, ISR_RDC);
00292
00293
00294 Delay16Cycles();
00295 }
00296
00297
00303 static int NicReset(void)
00304 {
00305 int tmp;
00306
00307
00308
00309 outr(PIO_PER, _BV(ASIX_RESET_PIN));
00310 outr(PIO_OER, _BV(ASIX_RESET_PIN));
00311 outr(PIO_SODR, _BV(ASIX_RESET_PIN));
00312 NutDelay(100);
00313 outr(PIO_CODR, _BV(ASIX_RESET_PIN));
00314
00315
00316 tmp = 10;
00317 while (1) {
00318 NutDelay(255);
00319 if (!(Asix_Read(TR) & TR_RST_B))
00320 break;
00321 if (tmp-- == 0)
00322 return -1;
00323 }
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335 return 0;
00336 }
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346 static int NicStart(CONST u_char * mac)
00347 {
00348 u_char i;
00349
00350
00351 if (NicReset())
00352 return -1;
00353
00354
00355 Asix_Write(CR, (CR_RD2 | CR_STOP));
00356
00357
00358 Asix_Write(PG0_DCR, DCR_WTS);
00359
00360
00361 Asix_Write(PG0_RBCR0, 0x00);
00362 Asix_Write(PG0_RBCR1, 0x00);
00363
00364
00365 Asix_Write(PG0_RCR, RCR_MON);
00366
00367
00368 Asix_Write(PG0_TCR, TCR_LB0);
00369
00370
00371 Asix_Write(PG0_BNRY, RXSTART_INIT);
00372 Asix_Write(PG0_PSTART, RXSTART_INIT);
00373 Asix_Write(PG0_PSTOP, RXSTOP_INIT);
00374
00375
00376 Asix_Write(PG0_ISR, 0xFF);
00377
00378
00379 Asix_Write(PG0_IMR, IMR_PRXE | IMR_PTXE | IMR_RXEE | IMR_TXEE | IMR_OVWE);
00380
00381
00382 Asix_Write(CR, (CR_PS0 | CR_RD2 | CR_STOP));
00383 Delay16Cycles();
00384
00385
00386 for (i = 0; i < 6; i++) {
00387 Asix_Write(PG1_PAR0 + i, mac[i]);
00388 }
00389
00390
00391 for (i = 0; i < 8; i++) {
00392 Asix_Write(PG1_MAR0 + i, 0x00);
00393 }
00394
00395
00396 Asix_Write(PG1_CPR, RXSTART_INIT + 1);
00397
00398
00399 Asix_Write(CR, (CR_RD2 | CR_START));
00400 Delay16Cycles();
00401
00402
00403 Asix_Write(GPOC, 0x10);
00404
00405
00406 if (Asix_Read(GPI) & 0x04) {
00407
00408 Asix_Write(PG0_TCR, TCR_FDU);
00409 }
00410 else {
00411
00412 Asix_Write(PG0_TCR, 0);
00413 }
00414
00415
00416
00417 Asix_Write(PG0_RCR, RCR_AB);
00418
00419 return 0;
00420 }
00421
00422
00423
00424
00425
00426 static void NicWrite(u_char * buf, u_short len)
00427 {
00428 register u_short *wp = (u_short *) buf;
00429
00430 if (len & 1)
00431 len++;
00432 len >>= 1;
00433
00434 while (len--) {
00435
00436 Asix_WriteWord(DATAPORT, *wp);
00437 wp++;
00438 }
00439
00440 }
00441
00442
00443
00444
00445
00446 static void NicRead(u_char * buf, u_short len)
00447 {
00448 register u_short *wp = (u_short *) buf;
00449
00450 if (len & 1)
00451 len++;
00452 len >>= 1;
00453
00454 while (len--) {
00455 *wp = Asix_ReadWord(DATAPORT);
00456
00457 wp++;
00458 }
00459
00460 }
00461
00462
00473 static NETBUF *NicGetPacket(void)
00474 {
00475 NETBUF *nb = 0;
00476 struct nic_pkt_header hdr;
00477 u_short count;
00478 u_char nextpg;
00479 u_char bnry;
00480 u_char curr;
00481 u_char drop = 0;
00482
00483
00484 NutEnterCritical();
00485
00486
00487
00488
00489
00490 curr = Asix_Read(PG0_CPR);
00491
00492
00493
00494
00495
00496
00497
00498
00499 if ((bnry = Asix_Read(PG0_BNRY) + 1) >= RXSTOP_INIT) {
00500
00501 bnry = RXSTART_INIT;
00502 }
00503 if (bnry == curr) {
00504
00505 NutJumpOutCritical();
00506 return 0;
00507 }
00508
00509
00510
00511 Asix_Write(PG0_RBCR0, sizeof(struct nic_pkt_header));
00512 Asix_Write(PG0_RBCR1, 0);
00513 Asix_Write(PG0_RSAR0, 0);
00514 Asix_Write(PG0_RSAR1, bnry);
00515 Asix_Write(CR, CR_START | CR_RD0);
00516 Delay16Cycles();
00517
00518 NicRead((u_char *) & hdr, sizeof(struct nic_pkt_header));
00519 NicCompleteDma();
00520
00521
00522
00523
00524
00525 if (hdr.ph_size < 60 + sizeof(struct nic_pkt_header) || hdr.ph_size > 1514 + sizeof(struct nic_pkt_header)) {
00526
00527 drop = 1;
00528 }
00529
00530
00531
00532
00533
00534
00535
00536
00537
00538
00539
00540
00541
00542
00543
00544 nextpg = bnry + (hdr.ph_size >> 8) + ((hdr.ph_size & 0xFF) != 0);
00545
00546
00547 if (nextpg >= RXSTOP_INIT) {
00548 nextpg -= RXSTOP_INIT;
00549 nextpg += RXSTART_INIT;
00550 }
00551 if (nextpg != hdr.ph_nextpg) {
00552 u_char nextpg1 = nextpg + 1;
00553 if (nextpg1 >= RXSTOP_INIT) {
00554 nextpg1 -= RXSTOP_INIT;
00555 nextpg1 += RXSTART_INIT;
00556 }
00557
00558
00559
00560 nextpg = nextpg1;
00561 }
00562
00563
00564
00565
00566
00567
00568
00569
00570 if (!drop && ((hdr.ph_status & 0x0E) == 0)) {
00571
00572
00573 count = hdr.ph_size - sizeof(struct nic_pkt_header);
00574
00575 if ((nb = NutNetBufAlloc(0, NBAF_DATALINK, count))) {
00576
00577
00578
00579
00580
00581 Asix_Write(PG0_RBCR0, count);
00582 Asix_Write(PG0_RBCR1, count >> 8);
00583 Asix_Write(PG0_RSAR0, sizeof(struct nic_pkt_header));
00584 Asix_Write(PG0_RSAR1, bnry);
00585
00586
00587
00588
00589 Asix_Write(CR, CR_START | CR_RD0);
00590 Delay16Cycles();
00591 NicRead(nb->nb_dl.vp, count);
00592 NicCompleteDma();
00593 }
00594 }
00595
00596
00597
00598
00599
00600 if (--nextpg < RXSTART_INIT)
00601 nextpg = RXSTOP_INIT - 1;
00602 Asix_Write(PG0_BNRY, nextpg);
00603 NutExitCritical();
00604 return nb;
00605
00606 }
00607
00608
00609
00610
00611
00612
00613
00614
00615
00616
00617
00618
00619
00620
00621
00622
00623
00624
00625
00626
00627 static u_char NicOverflow(volatile u_char * base)
00628 {
00629 u_int cr;
00630 u_int resend = 0;
00631 u_int curr;
00632
00633
00634
00635
00636
00637
00638 while (Asix_Read(CR) & CR_TXP);
00639 cr = Asix_Read(CR);
00640
00641
00642
00643
00644
00645 Asix_Write(CR, CR_STOP | CR_RD2 | CR_PS0);
00646 curr = Asix_Read(PG1_CPR);
00647 Asix_Write(CR, CR_STOP | CR_RD2);
00648
00649
00650 Asix_Write(PG0_RBCR0, 0);
00651 Asix_Write(PG0_RBCR1, 0);
00652
00653
00654 if ((cr & CR_TXP) && ((Asix_Read(PG0_ISR) & (ISR_PTX | ISR_TXE)) == 0)) {
00655 resend = 1;
00656 }
00657
00658
00659 Asix_Write(PG0_TCR, TCR_LB0);
00660 Asix_Write(CR, CR_START | CR_RD2);
00661
00662
00663
00664
00665
00666 if (--curr < TXSTART_INIT) {
00667 curr = RXSTOP_INIT - 1;
00668 }
00669 Asix_Write(PG0_BNRY, curr);
00670
00671
00672 Asix_Write(PG0_TCR, 0);
00673
00674
00675 if (resend) {
00676 Asix_Write(CR, CR_START | CR_TXP | CR_RD2);
00677 }
00678
00679
00680 Asix_Write(PG0_ISR, ISR_OVW);
00681 return resend;
00682 }
00683
00684
00685 static int NicPutPacket(NETBUF * nb)
00686 {
00687 u_short sz;
00688 u_short send_sz;
00689 static u_char first_put = 0;
00690 int tmp;
00691
00692
00693
00694
00695
00696 if (first_put != 1) {
00697 Asix_Write(CR, 0x21);
00698 NutDelay(1);
00699 Asix_Write(CR, 0x22);
00700 first_put = 1;
00701 }
00702
00703
00704
00705
00706
00707 sz = nb->nb_dl.sz + nb->nb_nw.sz + nb->nb_tp.sz + nb->nb_ap.sz;
00708 if (sz > 1518)
00709 return -1;
00710
00711
00712
00713
00714
00715
00716 send_sz = sz;
00717 if (sz <= 60)
00718 send_sz = 60;
00719
00720
00721 NutEnterCritical();
00722
00723 Asix_Write(CR, (CR_RD2 | CR_START));
00724
00725
00726
00727
00728
00729
00730
00731 tmp = 120;
00732 while ((Asix_Read(CR) & CR_TXP) && tmp--)
00733 NutDelay(1);
00734
00735
00736
00737 Asix_Write(PG0_RSAR0, 0x00);
00738 Asix_Write(PG0_RSAR1, TXSTART_INIT);
00739
00740
00741 Asix_Write(PG0_RBCR0, (unsigned char) (sz));
00742 Asix_Write(PG0_RBCR1, (unsigned char) (sz >> 8));
00743
00744
00745 Asix_Write(CR, (CR_RD1 | CR_START));
00746
00747
00748 NicWrite(nb->nb_dl.vp, nb->nb_dl.sz);
00749 NicWrite(nb->nb_nw.vp, nb->nb_nw.sz);
00750 NicWrite(nb->nb_tp.vp, nb->nb_tp.sz);
00751 NicWrite(nb->nb_ap.vp, nb->nb_ap.sz);
00752
00753
00754 NicCompleteDma();
00755
00756
00757 Asix_Write(PG0_ISR, (ISR_PTX | ISR_TXE));
00758 Delay16Cycles();
00759
00760
00761 Asix_Write(CR, CR_START | CR_RD2);
00762
00763 Asix_Write(PG0_TBCR0, (unsigned char) (send_sz));
00764 Asix_Write(PG0_TBCR1, (unsigned char) ((send_sz) >> 8));
00765 Asix_Write(PG0_TPSR, TXSTART_INIT);
00766
00767
00768 Asix_Write(CR, CR_START | CR_TXP | CR_RD2);
00769
00770
00771 NutExitCritical();
00772 return 0;
00773 }
00774
00775
00780 THREAD(NicRxAsix, arg)
00781 {
00782
00783 NUTDEVICE *dev;
00784 IFNET *ifn;
00785 NICINFO *ni;
00786 NETBUF *nb;
00787
00788
00789 dev = &devAx88796;
00790
00791 ifn = (IFNET *) dev->dev_icb;
00792 ni = (NICINFO *) dev->dev_dcb;
00793
00794 for (;;) {
00795 if (*((u_long *) (ifn->if_mac)) && *((u_long *) (ifn->if_mac)) != 0xFFFFFFFFUL) {
00796 break;
00797 }
00798 NutSleep(63);
00799 }
00800
00801 NutEnterCritical();
00802 NicStart(ifn->if_mac);
00803 NutExitCritical();
00804
00805
00806
00807 NutThreadSetPriority(9);
00808
00809 while (1) {
00810
00811 NutEventWait(&ni->ni_rx_rdy, 0);
00812
00813
00814
00815
00816
00817 do {
00818 nb = NicGetPacket();
00819
00820
00821 if (0) {
00822 NicStart(ifn->if_mac);
00823
00824 } else if (nb) {
00825 ni->ni_rx_packets++;
00826 (*ifn->if_recv) (dev, nb);
00827 }
00828 } while (nb);
00829 }
00830 }
00831
00832
00833
00834
00835
00836 static void NicInterrupt(void *arg)
00837 {
00838 u_char isr;
00839 volatile u_char *base = (u_char *) (((NUTDEVICE *) arg)->dev_base);
00840 NICINFO *ni = (NICINFO *) ((NUTDEVICE *) arg)->dev_dcb;
00841
00842 ni->ni_interrupts++;
00843
00844 isr = Asix_Read(PG0_ISR);
00845 Delay16Cycles();
00846 Asix_Write(PG0_ISR, isr);
00847
00848
00849
00850
00851
00852
00853
00854
00855
00856
00857
00858 if (isr & ISR_OVW) {
00859 ni->ni_rx_pending++;
00860 if (NicOverflow(base))
00861 ni->ni_tx_bsy++;
00862 else {
00863 NutEventPostAsync(&ni->ni_tx_rdy);
00864 }
00865 ni->ni_overruns++;
00866 } else {
00867
00868
00869
00870
00871
00872
00873 if (isr & (ISR_PTX | ISR_TXE)) {
00874 ni->ni_tx_bsy = 0;
00875 }
00876
00877
00878
00879
00880
00881 if (isr & ISR_PRX) {
00882 ni->ni_rx_pending++;
00883
00884 NutEventPostFromIrq(&ni->ni_rx_rdy);
00885 }
00886
00887
00888 if (isr & ISR_RXE) {
00889 if (Asix_Read(PG0_RSR) & RSR_FAE)
00890 ni->ni_rx_frame_errors++;
00891 if (Asix_Read(PG0_RSR) & RSR_CR)
00892 ni->ni_rx_crc_errors++;
00893 if (Asix_Read(PG0_RSR) & RSR_MPA)
00894 ni->ni_rx_missed_errors++;
00895 }
00896 }
00897 }
00898
00899 void NicInterruptEntry(void) __attribute__ ((naked));
00900 void NicInterruptEntry(void)
00901 {
00902 IRQ_ENTRY();
00903
00904 NicInterrupt(&devAx88796);
00905 IRQ_EXIT();
00906 }
00907
00908
00919 int AsixOutput(NUTDEVICE * dev, NETBUF * nb)
00920 {
00921 int rc = -1;
00922 NICINFO *ni = (NICINFO *) dev->dev_dcb;
00923
00924 if (NicPutPacket(nb) == 0) {
00925 ni->ni_tx_packets++;
00926 rc = 0;
00927 }
00928 return rc;
00929 }
00930
00931
00949 int AsixInit(NUTDEVICE * dev)
00950 {
00951
00952 confnet.cd_size = sizeof(CONFNET);
00953 strcpy(confnet.cd_name, "eth0");
00954 memset(confnet.cdn_mac, 0xFF, 6);
00955
00956
00957
00958 memset(dev->dev_dcb, 0, sizeof(NICINFO));
00959
00960
00961
00962
00963
00964 NutThreadCreate("rxi5", NicRxAsix, dev, 1024);
00965
00966 outr(PIO_PDR, _BV(9));
00967
00968
00969 outr(AIC_IDCR, _BV(IRQ0_ID));
00970
00971 outr(AIC_SVR(IRQ0_ID), (unsigned int) NicInterruptEntry);
00972
00973
00974 outr(AIC_SMR(IRQ0_ID), (AIC_SRCTYPE_EXT_NEGATIVE_EDGE | 5));
00975
00976 outr(AIC_ICCR, _BV(IRQ0_ID));
00977
00978 outr(AIC_IECR, _BV(IRQ0_ID));
00979
00980
00981 return 0;
00982 }
00983