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