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
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075 #include <arch/arm.h>
00076
00077 #include <string.h>
00078
00079
00080 #include <sys/atom.h>
00081 #include <sys/heap.h>
00082 #include <sys/thread.h>
00083 #include <sys/event.h>
00084 #include <sys/timer.h>
00085 #include <sys/confnet.h>
00086
00087 #include <dev/irqreg.h>
00088 #include <dev/ax88796.h>
00089 #include "reg_ax88796.h"
00090
00091 #define ASIX_RESET_PIN 10
00092
00093 static NICINFO dcb_eth0;
00094
00099
00100
00106 static IFNET ifn_eth0 = {
00107 IFT_ETHER,
00108 0,
00109 {0, 0, 0, 0, 0, 0},
00110 0,
00111 0,
00112 0,
00113 ETHERMTU,
00114 0,
00115 0,
00116 0,
00117 NutEtherInput,
00118 AsixOutput,
00119 NutEtherOutput
00120 };
00121
00131 NUTDEVICE devAx88796 = {
00132 0,
00133 {'e', 't', 'h', '0', 0, 0, 0, 0, 0},
00134 IFTYP_NET,
00135 0,
00136 0,
00137 &ifn_eth0,
00138 &dcb_eth0,
00139 AsixInit,
00140 0,
00141 0,
00142 0,
00143 0,
00144 0,
00145 0
00146 };
00147
00151 struct nic_pkt_header {
00152 uint8_t ph_status;
00153 uint8_t ph_nextpg;
00154 uint16_t ph_size;
00155 };
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166 void Delay16Cycles(void)
00167 {
00168 _NOP();
00169 _NOP();
00170 _NOP();
00171 _NOP();
00172 _NOP();
00173 _NOP();
00174 _NOP();
00175 _NOP();
00176 _NOP();
00177 _NOP();
00178 _NOP();
00179 _NOP();
00180 _NOP();
00181 _NOP();
00182 _NOP();
00183 _NOP();
00184 }
00185
00186
00192 static uint16_t MIIPutGet(uint16_t data, uint8_t bitCount)
00193 {
00194 uint16_t rc = 0;
00195 uint16_t mask;
00196 uint8_t i;
00197
00198 mask = 1 << (bitCount - 1);
00199
00200 for (i = 0; i < bitCount; i++) {
00201
00202
00203 if (data & mask) {
00204 Asix_Write(MII_EEP, (Asix_Read(MII_EEP) | MII_EEP_MDO));
00205 } else {
00206 Asix_Write(MII_EEP, (Asix_Read(MII_EEP) & ~(MII_EEP_MDO)));
00207 }
00208
00209 Asix_Write(MII_EEP, (Asix_Read(MII_EEP) | MII_EEP_MDC));
00210 Delay16Cycles();
00211
00212 data <<= 1;
00213 rc <<= 1;
00214 rc |= (Asix_Read(MII_EEP) & MII_EEP_MDI) != 0;
00215 Asix_Write(MII_EEP, (Asix_Read(MII_EEP) & ~(MII_EEP_MDC)));
00216 }
00217 return rc;
00218 }
00219
00220
00227 uint16_t NicPhyRead(uint8_t reg)
00228 {
00229 uint16_t rc = 0;
00230
00231
00232 Asix_Write(CR, (Asix_Read(CR) & ~(CR_PS0)));
00233
00234
00235 MIIPutGet(0xFFFF, 16);
00236 MIIPutGet(0xFFFF, 16);
00237
00238
00239 MIIPutGet(0xD0, 9);
00240
00241
00242 MIIPutGet(reg, 5);
00243
00244
00245 MIIPutGet(0x0, 1);
00246
00247
00248 rc = MIIPutGet(0, 16);
00249
00250 return rc;
00251 }
00252
00253
00262 void NicPhyWrite(uint8_t reg, uint16_t val)
00263 {
00264
00265
00266 Asix_Write(CR, (Asix_Read(CR) & ~(CR_PS0)));
00267
00268
00269 MIIPutGet(0xFFFF, 16);
00270 MIIPutGet(0xFFFF, 16);
00271
00272
00273 MIIPutGet(0xB0, 9);
00274
00275
00276 MIIPutGet(reg, 5);
00277
00278
00279 MIIPutGet(0x02, 2);
00280
00281
00282 MIIPutGet(val, 16);
00283 }
00284
00285
00286
00290 static void NicCompleteDma(void)
00291 {
00292 uint8_t i;
00293
00294
00295 do {
00296 i = Asix_Read(PG0_ISR);
00297 } while ((i & ISR_RDC) == 0);
00298
00299
00300 Asix_Write(CR, CR_START | CR_RD2);
00301
00302
00303 Asix_Write(PG0_ISR, ISR_RDC);
00304
00305
00306 Delay16Cycles();
00307 }
00308
00309
00315 static int NicReset(void)
00316 {
00317 int tmp;
00318
00319
00320
00321 outr(PIO_PER, _BV(ASIX_RESET_PIN));
00322 outr(PIO_OER, _BV(ASIX_RESET_PIN));
00323 outr(PIO_SODR, _BV(ASIX_RESET_PIN));
00324 NutDelay(100);
00325 outr(PIO_CODR, _BV(ASIX_RESET_PIN));
00326
00327
00328 tmp = 10;
00329 while (1) {
00330 NutDelay(255);
00331 if (!(Asix_Read(TR) & TR_RST_B))
00332 break;
00333 if (tmp-- == 0)
00334 return -1;
00335 }
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347 return 0;
00348 }
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358 static int NicStart(CONST uint8_t * mac)
00359 {
00360 uint8_t i;
00361
00362
00363 if (NicReset())
00364 return -1;
00365
00366
00367 Asix_Write(CR, (CR_RD2 | CR_STOP));
00368
00369
00370 Asix_Write(PG0_DCR, DCR_WTS);
00371
00372
00373 Asix_Write(PG0_RBCR0, 0x00);
00374 Asix_Write(PG0_RBCR1, 0x00);
00375
00376
00377 Asix_Write(PG0_RCR, RCR_MON);
00378
00379
00380 Asix_Write(PG0_TCR, TCR_LB0);
00381
00382
00383 Asix_Write(PG0_BNRY, RXSTART_INIT);
00384 Asix_Write(PG0_PSTART, RXSTART_INIT);
00385 Asix_Write(PG0_PSTOP, RXSTOP_INIT);
00386
00387
00388 Asix_Write(PG0_ISR, 0xFF);
00389
00390
00391 Asix_Write(PG0_IMR, IMR_PRXE | IMR_PTXE | IMR_RXEE | IMR_TXEE | IMR_OVWE);
00392
00393
00394 Asix_Write(CR, (CR_PS0 | CR_RD2 | CR_STOP));
00395 Delay16Cycles();
00396
00397
00398 for (i = 0; i < 6; i++) {
00399 Asix_Write(PG1_PAR0 + i, mac[i]);
00400 }
00401
00402
00403 for (i = 0; i < 8; i++) {
00404 Asix_Write(PG1_MAR0 + i, 0x00);
00405 }
00406
00407
00408 Asix_Write(PG1_CPR, RXSTART_INIT + 1);
00409
00410
00411 Asix_Write(CR, (CR_RD2 | CR_START));
00412 Delay16Cycles();
00413
00414
00415 Asix_Write(GPOC, 0x10);
00416
00417
00418 if (Asix_Read(GPI) & 0x04) {
00419
00420 Asix_Write(PG0_TCR, TCR_FDU);
00421 }
00422 else {
00423
00424 Asix_Write(PG0_TCR, 0);
00425 }
00426
00427
00428
00429 Asix_Write(PG0_RCR, RCR_AB);
00430
00431 return 0;
00432 }
00433
00434
00435
00436
00437
00438 static void NicWrite(uint8_t * buf, uint16_t len)
00439 {
00440 register uint16_t *wp = (uint16_t *) buf;
00441
00442 if (len & 1)
00443 len++;
00444 len >>= 1;
00445
00446 while (len--) {
00447
00448 Asix_WriteWord(DATAPORT, *wp);
00449 wp++;
00450 }
00451
00452 }
00453
00454
00455
00456
00457
00458 static void NicRead(uint8_t * buf, uint16_t len)
00459 {
00460 register uint16_t *wp = (uint16_t *) buf;
00461
00462 if (len & 1)
00463 len++;
00464 len >>= 1;
00465
00466 while (len--) {
00467 *wp = Asix_ReadWord(DATAPORT);
00468
00469 wp++;
00470 }
00471
00472 }
00473
00474
00485 static NETBUF *NicGetPacket(void)
00486 {
00487 NETBUF *nb = 0;
00488 struct nic_pkt_header hdr;
00489 uint16_t count;
00490 uint8_t nextpg;
00491 uint8_t bnry;
00492 uint8_t curr;
00493 uint8_t drop = 0;
00494
00495
00496 NutEnterCritical();
00497
00498
00499
00500
00501
00502 curr = Asix_Read(PG0_CPR);
00503
00504
00505
00506
00507
00508
00509
00510
00511 if ((bnry = Asix_Read(PG0_BNRY) + 1) >= RXSTOP_INIT) {
00512
00513 bnry = RXSTART_INIT;
00514 }
00515 if (bnry == curr) {
00516
00517 NutJumpOutCritical();
00518 return 0;
00519 }
00520
00521
00522
00523 Asix_Write(PG0_RBCR0, sizeof(struct nic_pkt_header));
00524 Asix_Write(PG0_RBCR1, 0);
00525 Asix_Write(PG0_RSAR0, 0);
00526 Asix_Write(PG0_RSAR1, bnry);
00527 Asix_Write(CR, CR_START | CR_RD0);
00528 Delay16Cycles();
00529
00530 NicRead((uint8_t *) & hdr, sizeof(struct nic_pkt_header));
00531 NicCompleteDma();
00532
00533
00534
00535
00536
00537 if (hdr.ph_size < 60 + sizeof(struct nic_pkt_header) || hdr.ph_size > 1514 + sizeof(struct nic_pkt_header)) {
00538
00539 drop = 1;
00540 }
00541
00542
00543
00544
00545
00546
00547
00548
00549
00550
00551
00552
00553
00554
00555
00556 nextpg = bnry + (hdr.ph_size >> 8) + ((hdr.ph_size & 0xFF) != 0);
00557
00558
00559 if (nextpg >= RXSTOP_INIT) {
00560 nextpg -= RXSTOP_INIT;
00561 nextpg += RXSTART_INIT;
00562 }
00563 if (nextpg != hdr.ph_nextpg) {
00564 uint8_t nextpg1 = nextpg + 1;
00565 if (nextpg1 >= RXSTOP_INIT) {
00566 nextpg1 -= RXSTOP_INIT;
00567 nextpg1 += RXSTART_INIT;
00568 }
00569
00570
00571
00572 nextpg = nextpg1;
00573 }
00574
00575
00576
00577
00578
00579
00580
00581
00582 if (!drop && ((hdr.ph_status & 0x0E) == 0)) {
00583
00584
00585 count = hdr.ph_size - sizeof(struct nic_pkt_header);
00586
00587 if ((nb = NutNetBufAlloc(0, NBAF_DATALINK, count))) {
00588
00589
00590
00591
00592
00593 Asix_Write(PG0_RBCR0, count);
00594 Asix_Write(PG0_RBCR1, count >> 8);
00595 Asix_Write(PG0_RSAR0, sizeof(struct nic_pkt_header));
00596 Asix_Write(PG0_RSAR1, bnry);
00597
00598
00599
00600
00601 Asix_Write(CR, CR_START | CR_RD0);
00602 Delay16Cycles();
00603 NicRead(nb->nb_dl.vp, count);
00604 NicCompleteDma();
00605 }
00606 }
00607
00608
00609
00610
00611
00612 if (--nextpg < RXSTART_INIT)
00613 nextpg = RXSTOP_INIT - 1;
00614 Asix_Write(PG0_BNRY, nextpg);
00615 NutExitCritical();
00616 return nb;
00617
00618 }
00619
00620
00621
00622
00623
00624
00625
00626
00627
00628
00629
00630
00631
00632
00633
00634
00635
00636
00637
00638
00639 static uint8_t NicOverflow(volatile uint8_t * base)
00640 {
00641 unsigned int cr;
00642 unsigned int resend = 0;
00643 unsigned int curr;
00644
00645
00646
00647
00648
00649
00650 while (Asix_Read(CR) & CR_TXP);
00651 cr = Asix_Read(CR);
00652
00653
00654
00655
00656
00657 Asix_Write(CR, CR_STOP | CR_RD2 | CR_PS0);
00658 curr = Asix_Read(PG1_CPR);
00659 Asix_Write(CR, CR_STOP | CR_RD2);
00660
00661
00662 Asix_Write(PG0_RBCR0, 0);
00663 Asix_Write(PG0_RBCR1, 0);
00664
00665
00666 if ((cr & CR_TXP) && ((Asix_Read(PG0_ISR) & (ISR_PTX | ISR_TXE)) == 0)) {
00667 resend = 1;
00668 }
00669
00670
00671 Asix_Write(PG0_TCR, TCR_LB0);
00672 Asix_Write(CR, CR_START | CR_RD2);
00673
00674
00675
00676
00677
00678 if (--curr < TXSTART_INIT) {
00679 curr = RXSTOP_INIT - 1;
00680 }
00681 Asix_Write(PG0_BNRY, curr);
00682
00683
00684 Asix_Write(PG0_TCR, 0);
00685
00686
00687 if (resend) {
00688 Asix_Write(CR, CR_START | CR_TXP | CR_RD2);
00689 }
00690
00691
00692 Asix_Write(PG0_ISR, ISR_OVW);
00693 return resend;
00694 }
00695
00696
00697 static int NicPutPacket(NETBUF * nb)
00698 {
00699 uint16_t sz;
00700 uint16_t send_sz;
00701 static uint8_t first_put = 0;
00702 int tmp;
00703
00704
00705
00706
00707
00708 if (first_put != 1) {
00709 Asix_Write(CR, 0x21);
00710 NutDelay(1);
00711 Asix_Write(CR, 0x22);
00712 first_put = 1;
00713 }
00714
00715
00716
00717
00718
00719 sz = nb->nb_dl.sz + nb->nb_nw.sz + nb->nb_tp.sz + nb->nb_ap.sz;
00720 if (sz > 1518)
00721 return -1;
00722
00723
00724
00725
00726
00727
00728 send_sz = sz;
00729 if (sz <= 60)
00730 send_sz = 60;
00731
00732
00733 NutEnterCritical();
00734
00735 Asix_Write(CR, (CR_RD2 | CR_START));
00736
00737
00738
00739
00740
00741
00742
00743 tmp = 120;
00744 while ((Asix_Read(CR) & CR_TXP) && tmp--)
00745 NutDelay(1);
00746
00747
00748
00749 Asix_Write(PG0_RSAR0, 0x00);
00750 Asix_Write(PG0_RSAR1, TXSTART_INIT);
00751
00752
00753 Asix_Write(PG0_RBCR0, (unsigned char) (sz));
00754 Asix_Write(PG0_RBCR1, (unsigned char) (sz >> 8));
00755
00756
00757 Asix_Write(CR, (CR_RD1 | CR_START));
00758
00759
00760 NicWrite(nb->nb_dl.vp, nb->nb_dl.sz);
00761 NicWrite(nb->nb_nw.vp, nb->nb_nw.sz);
00762 NicWrite(nb->nb_tp.vp, nb->nb_tp.sz);
00763 NicWrite(nb->nb_ap.vp, nb->nb_ap.sz);
00764
00765
00766 NicCompleteDma();
00767
00768
00769 Asix_Write(PG0_ISR, (ISR_PTX | ISR_TXE));
00770 Delay16Cycles();
00771
00772
00773 Asix_Write(CR, CR_START | CR_RD2);
00774
00775 Asix_Write(PG0_TBCR0, (unsigned char) (send_sz));
00776 Asix_Write(PG0_TBCR1, (unsigned char) ((send_sz) >> 8));
00777 Asix_Write(PG0_TPSR, TXSTART_INIT);
00778
00779
00780 Asix_Write(CR, CR_START | CR_TXP | CR_RD2);
00781
00782
00783 NutExitCritical();
00784 return 0;
00785 }
00786
00787
00792 THREAD(NicRxAsix, arg)
00793 {
00794
00795 NUTDEVICE *dev;
00796 IFNET *ifn;
00797 NICINFO *ni;
00798 NETBUF *nb;
00799
00800
00801 dev = &devAx88796;
00802
00803 ifn = (IFNET *) dev->dev_icb;
00804 ni = (NICINFO *) dev->dev_dcb;
00805
00806
00807
00808
00809
00810
00811 while (!ETHER_IS_UNICAST(ifn->if_mac)) {
00812 NutSleep(10);
00813 }
00814
00815 NutEnterCritical();
00816 NicStart(ifn->if_mac);
00817 NutExitCritical();
00818
00819
00820
00821 NutThreadSetPriority(9);
00822
00823 while (1) {
00824
00825 NutEventWait(&ni->ni_rx_rdy, 0);
00826
00827
00828
00829
00830
00831 do {
00832 nb = NicGetPacket();
00833
00834
00835 if (0) {
00836 NicStart(ifn->if_mac);
00837
00838 } else if (nb) {
00839 ni->ni_rx_packets++;
00840 (*ifn->if_recv) (dev, nb);
00841 }
00842 } while (nb);
00843 }
00844 }
00845
00846
00847
00848
00849
00850 static void NicInterrupt(void *arg)
00851 {
00852 uint8_t isr;
00853 volatile uint8_t *base = (uint8_t *) (((NUTDEVICE *) arg)->dev_base);
00854 NICINFO *ni = (NICINFO *) ((NUTDEVICE *) arg)->dev_dcb;
00855
00856 ni->ni_interrupts++;
00857
00858 isr = Asix_Read(PG0_ISR);
00859 Delay16Cycles();
00860 Asix_Write(PG0_ISR, isr);
00861
00862
00863
00864
00865
00866
00867
00868
00869
00870
00871
00872 if (isr & ISR_OVW) {
00873 ni->ni_rx_pending++;
00874 if (NicOverflow(base))
00875 ni->ni_tx_bsy++;
00876 else {
00877 NutEventPostAsync(&ni->ni_tx_rdy);
00878 }
00879 ni->ni_overruns++;
00880 } else {
00881
00882
00883
00884
00885
00886
00887 if (isr & (ISR_PTX | ISR_TXE)) {
00888 ni->ni_tx_bsy = 0;
00889 }
00890
00891
00892
00893
00894
00895 if (isr & ISR_PRX) {
00896 ni->ni_rx_pending++;
00897
00898 NutEventPostFromIrq(&ni->ni_rx_rdy);
00899 }
00900
00901
00902 if (isr & ISR_RXE) {
00903 if (Asix_Read(PG0_RSR) & RSR_FAE)
00904 ni->ni_rx_frame_errors++;
00905 if (Asix_Read(PG0_RSR) & RSR_CR)
00906 ni->ni_rx_crc_errors++;
00907 if (Asix_Read(PG0_RSR) & RSR_MPA)
00908 ni->ni_rx_missed_errors++;
00909 }
00910 }
00911 }
00912
00913 void NicInterruptEntry(void) __attribute__ ((naked));
00914 void NicInterruptEntry(void)
00915 {
00916 IRQ_ENTRY();
00917
00918 NicInterrupt(&devAx88796);
00919 IRQ_EXIT();
00920 }
00921
00922
00933 int AsixOutput(NUTDEVICE * dev, NETBUF * nb)
00934 {
00935 int rc = -1;
00936 NICINFO *ni = (NICINFO *) dev->dev_dcb;
00937
00938 if (NicPutPacket(nb) == 0) {
00939 ni->ni_tx_packets++;
00940 rc = 0;
00941 }
00942 return rc;
00943 }
00944
00945
00963 int AsixInit(NUTDEVICE * dev)
00964 {
00965
00966 confnet.cd_size = sizeof(CONFNET);
00967 strcpy(confnet.cd_name, "eth0");
00968 memset(confnet.cdn_mac, 0xFF, 6);
00969
00970
00971
00972 memset(dev->dev_dcb, 0, sizeof(NICINFO));
00973
00974
00975
00976
00977
00978 NutThreadCreate("rxi5", NicRxAsix, dev, 1024);
00979
00980 outr(PIO_PDR, _BV(9));
00981
00982
00983 outr(AIC_IDCR, _BV(IRQ0_ID));
00984
00985 outr(AIC_SVR(IRQ0_ID), (unsigned int) NicInterruptEntry);
00986
00987
00988 outr(AIC_SMR(IRQ0_ID), (AIC_SRCTYPE_EXT_NEGATIVE_EDGE | 5));
00989
00990 outr(AIC_ICCR, _BV(IRQ0_ID));
00991
00992 outr(AIC_IECR, _BV(IRQ0_ID));
00993
00994
00995 return 0;
00996 }
00997