]> git.kernelconcepts.de Git - karo-tx-redboot.git/blobdiff - packages/devs/eth/rltk/8139/v2_0/src/if_8139.c
unified MX27, MX25, MX37 trees
[karo-tx-redboot.git] / packages / devs / eth / rltk / 8139 / v2_0 / src / if_8139.c
index 79a7ea40670cf1fb48670ded45a8a20a66e7bf0e..a2de3300992f25eae285b65fc7c4aae8e9828370 100644 (file)
 #include "if_8139.h"
 
 /* Which interrupts we will handle */
-#define RLTK8139_IRQ (IR_SERR|IR_FOVW|IR_RXOVW|IR_TER|IR_TOK|IR_RER|IR_ROK)
+#define RLTK8139_IRQ (IR_SERR|IR_FOVW|IR_RXOVW|IR_TER|IR_TOK|IR_RER|IR_ROK|IR_FUN)
 
 /* Allow platform-specific configuration of the driver */
 #ifndef CYGDAT_DEVS_ETH_RLTK_8139_INL
@@ -177,10 +177,44 @@ static void rltk8139_deliver(struct eth_drv_sc *sc);
 static void rltk8139_poll(struct eth_drv_sc *sc);
 static int rltk8139_int_vector(struct eth_drv_sc *sc);
 
+#ifdef CYGPKG_DEVS_ETH_RLTK_8139_WRITE_EEPROM
+static cyg_uint16 rltk8139_eeprom_read( char *cpErAddr, cyg_uint8 Cmd, cyg_uint8 RomAdr );
+static void rltk8139_eeprom_write( char *cpErAddr, cyg_uint8 Cmd, cyg_uint8 RomAdr, cyg_uint16 SrcData );
+#endif
+
 #ifdef DEBUG_RLTK8139_DRIVER
 void rltk8139_print_state(struct eth_drv_sc *sc);
 #endif
 
+#ifdef CYGPKG_DEVS_ETH_RLTK_8139_WRITE_EEPROM
+#define EEPROM_CMD_READ         0x06  // eeprom read command
+#define EEPROM_CMD_WRITE        0x05  // eeprom write command
+#define EEPROM_PG_ON            0x80
+#define EEPROM_PG_EECS          0x08
+#define EEPROM_PG_EESK          0x04
+#define EEPROM_PG_EEDI          0x02
+#define EEPROM_PG_EEDO          0x01
+#define EEPROM_WR_BUSY_RETRIES  100   // ready wait re-try count
+
+#define        EEPROM_MASK(_param0_,_param1_)            ((_param0_ & _param1_) ? EEPROM_PG_EEDI : 0 )
+
+
+#define EEPROM_WR_DATA(_addr_,_txdata_)           HAL_WRITE_UINT8(_addr_,_txdata_);
+
+#define EEPROM_WR_DATAPULSE(_addr_,_txdata_)      HAL_WRITE_UINT8(_addr_,_txdata_); \
+                                                  cyg_thread_delay(0); \
+                                                  HAL_WRITE_UINT8(_addr_,_txdata_ | EEPROM_PG_EESK);
+
+#define EEPROM_RD_DATA(_addr_,_txdata_,_rxdata_)  { \
+                                                  cyg_uint16  read_data; \
+                                                  HAL_WRITE_UINT8(_addr_,_txdata_); \
+                                                  cyg_thread_delay(1); \
+                                                  HAL_READ_UINT8(_addr_, read_data); \
+                                                  _rxdata_ <<= 1; \
+                                                  _rxdata_ |= ((read_data & EEPROM_PG_EEDO) ? 0x0001 : 0x0000 ); \
+                                                  HAL_WRITE_UINT8(_addr_,_txdata_ | EEPROM_PG_EESK); }
+#endif
+
 /*
  * Define inline functions to access the card. This will also handle
  * endianess issues in one place. This code was lifted from the eCos
@@ -274,11 +308,12 @@ static inline cyg_uint32 INL(cyg_uint32 io_address)
  * Table of all known PCI device/vendor ID combinations for the RealTek 8139.
  * Add them as you get to know them.
  */
-#define CYGNUM_DEVS_ETH_RLTK_8139_KNOWN_ALIASES 2
+#define CYGNUM_DEVS_ETH_RLTK_8139_KNOWN_ALIASES 3
 static pci_identifier_t
 known_8139_aliases[CYGNUM_DEVS_ETH_RLTK_8139_KNOWN_ALIASES] = {
-  { 0x10ec, 0x8139, NULL }, /* This is the offical RealTek vendor/device code */
-  { 0x11db, 0x1234, NULL} /* SEGA DreamCast BroadBandAdapter */
+  { 0x10ec, 0x8139, NULL }, /* This is the official RealTek vendor/device code of 8139D(L) */
+  { 0x11db, 0x1234, NULL}, /* SEGA DreamCast BroadBandAdapter */
+  { 0x10ec, 0x8129, NULL } /* This is the official RealTek vendor/device code of 8139C(L) */
 };
 
 
@@ -346,7 +381,8 @@ rltk8139_find(int n_th, struct eth_drv_sc *sc)
      * Note that we use the generic eth_drv_dsr routine instead of
      * our own.
      */
-    cyg_drv_interrupt_create(rltk8139_info->vector, 0,
+    cyg_drv_interrupt_create(rltk8139_info->vector,
+                             rltk8139_info->isr_priority,
                              (CYG_ADDRWORD)sc,
                              rltk8139_isr,
                              eth_drv_dsr,
@@ -776,6 +812,11 @@ rltk8139_control(struct eth_drv_sc *sc, unsigned long key, void *data,
   int i;
   Rltk8139_t *rltk8139_info;
 
+#ifdef CYGPKG_DEVS_ETH_RLTK_8139_WRITE_EEPROM
+  cyg_uint16 WrData, RdData;
+  cyg_uint8  *pSrcData;
+  int iRetry;
+#endif
 
 #ifdef DEBUG_RLTK8139_DRIVER
   diag_printf("rltk8139_control(%08x, %lx)\n", sc, key);
@@ -794,6 +835,26 @@ rltk8139_control(struct eth_drv_sc *sc, unsigned long key, void *data,
       rltk8139_info->mac[i] = *(((cyg_uint8 *)data) + i);
       OUTB(rltk8139_info->mac[i], rltk8139_info->base_address + IDR0 + i);
     }
+
+#ifdef CYGPKG_DEVS_ETH_RLTK_8139_WRITE_EEPROM
+    pSrcData = (cyg_uint8 *)data;
+    for(i = 0; i < 3; i++){
+      WrData  = ((cyg_uint16)(*pSrcData++)) & 0xff;
+      WrData |=  ((cyg_uint16)(*pSrcData++)) << 8;
+      for( iRetry = 0; iRetry < 3; iRetry++){
+        rltk8139_eeprom_write(
+                         (char *)(rltk8139_info->base_address + CR9346),
+                                           EEPROM_CMD_WRITE, i + 7, WrData);
+        RdData = rltk8139_eeprom_read(
+                         (char *)(rltk8139_info->base_address + CR9346),
+                                           EEPROM_CMD_READ, i + 7);
+        if( RdData == WrData ){
+          break;
+        }
+      }
+    }
+#endif
+
     return 0;
 #endif
 
@@ -936,8 +997,8 @@ rltk8139_send(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len,
    * this happens so seldomly that it's simply not worth the extra
    * runtime check.
    */
-  tx_buffer = CYGARC_UNCACHED_ADDRESS(rltk8139_info->tx_buffer
-                                      + TX_BUF_SIZE * desc);
+  tx_buffer = (cyg_uint8 *)CYGARC_UNCACHED_ADDRESS(rltk8139_info->tx_buffer
+                                                   + TX_BUF_SIZE * desc);
   rltk8139_info->tx_desc_key[desc] = key;
 
   /*
@@ -1201,7 +1262,9 @@ rltk8139_deliver(struct eth_drv_sc *sc)
          * doesn't have to redetermine this information. Then, inform
          * the generic ethernet driver about the packet.
          */
-        rltk8139_info->rx_current = CYGARC_UNCACHED_ADDRESS(rltk8139_info->rx_ring + rx_pos + 4);
+        rltk8139_info->rx_current = 
+          (cyg_uint8 *)CYGARC_UNCACHED_ADDRESS(rltk8139_info->rx_ring + 
+                                               rx_pos + 4);
         rltk8139_info->rx_size = length;
 
         /* Tell eCos about the packet */
@@ -1246,6 +1309,17 @@ rltk8139_deliver(struct eth_drv_sc *sc)
     return;
   }
 
+  if (status & IR_FUN) {
+    /*
+     * Packet underrun or link change interrupt.
+     * A cable was packet underrun or re-connected ?
+     */
+#ifdef DEBUG_RLTK8139_DRIVER
+    diag_printf("rltk8139_deliver(%s): packet underrun or link change\n",
+                sc->dev_name);
+#endif
+  }
+
 #ifndef CYGPKG_IO_ETH_DRIVERS_STAND_ALONE
   /* Finally, reenable interrupts */
 #ifdef CYGPKG_DEVS_ETH_RLTK_8139_MASK_INTERRUPTS_IN_8139
@@ -1317,3 +1391,137 @@ rltk8139_print_state(struct eth_drv_sc *sc) {
   }
 }
 #endif
+
+
+#ifdef CYGPKG_DEVS_ETH_RLTK_8139_WRITE_EEPROM
+/*
+ * Read mac_address from EEPROM.
+ */
+static cyg_uint16
+rltk8139_eeprom_read( char *rtl_addr, cyg_uint8 eeprom_cmd, cyg_uint8 eeprom_addr )
+{
+cyg_uint8   read_data;                   // read from eeprom bit data
+cyg_uint8   org_param;                   // original register parameter
+cyg_uint8   mask_bit8;                   // mask bit
+int         icount;                      // for loop counter
+
+    // get old parameter
+    HAL_READ_UINT8( rtl_addr, org_param );
+
+    // ready
+    EEPROM_WR_DATAPULSE( rtl_addr, EEPROM_PG_ON );
+
+    // set command
+    mask_bit8 = 0x04;
+    for(icount = 0; icount < 3; icount++){
+        EEPROM_WR_DATAPULSE( rtl_addr, EEPROM_PG_ON | EEPROM_PG_EECS | EEPROM_MASK( mask_bit8, eeprom_cmd ));
+        mask_bit8 >>= 1;
+    }
+
+    // set address
+    mask_bit8 = 0x20;
+    for(icount = 0; icount < 6; icount++){
+        EEPROM_WR_DATAPULSE( rtl_addr, EEPROM_PG_ON | EEPROM_PG_EECS | EEPROM_MASK( mask_bit8, eeprom_addr ));
+        mask_bit8 >>= 1;
+    }
+
+    // read data
+    read_data = 0;
+    for(icount = 0; icount < 16; icount++){
+        EEPROM_RD_DATA( rtl_addr, EEPROM_PG_ON | EEPROM_PG_EECS, read_data );
+    }
+
+    // close
+    EEPROM_WR_DATA( rtl_addr, EEPROM_PG_ON | EEPROM_PG_EECS );
+    EEPROM_WR_DATA( rtl_addr, EEPROM_PG_ON );
+
+    // put old parameter
+    HAL_WRITE_UINT8(rtl_addr, org_param);
+
+    return(read_data);
+}
+
+
+/*
+ * Write in mac_address at EEPROM.
+ */
+static void
+rltk8139_eeprom_write( char *rtl_addr, cyg_uint8 eeprom_cmd, cyg_uint8 eeprom_addr, cyg_uint16 src_data )
+{
+cyg_uint8   read_data;                   // read from eeprom bit data
+cyg_uint8   org_param;                   // original register parameter
+cyg_uint8   mask_bit8;                   // mask bit
+cyg_uint16  mask_bit16;                  // mask bit for write data
+int         icount;                      // for loop counter
+
+    // get old parameter
+    HAL_READ_UINT8( rtl_addr, org_param );
+
+    // ready
+    EEPROM_WR_DATA( rtl_addr, EEPROM_PG_ON );
+    EEPROM_WR_DATA( rtl_addr, EEPROM_PG_ON | EEPROM_PG_EESK );
+    EEPROM_WR_DATA( rtl_addr, EEPROM_PG_ON );
+
+    // set EWEN (eeprom write enable)
+    EEPROM_WR_DATAPULSE( rtl_addr, EEPROM_PG_ON | EEPROM_PG_EECS | EEPROM_PG_EEDI );
+    EEPROM_WR_DATAPULSE( rtl_addr, EEPROM_PG_ON | EEPROM_PG_EECS );
+    EEPROM_WR_DATAPULSE( rtl_addr, EEPROM_PG_ON | EEPROM_PG_EECS );
+    EEPROM_WR_DATAPULSE( rtl_addr, EEPROM_PG_ON | EEPROM_PG_EECS | EEPROM_PG_EEDI );
+    EEPROM_WR_DATAPULSE( rtl_addr, EEPROM_PG_ON | EEPROM_PG_EECS | EEPROM_PG_EEDI );
+    EEPROM_WR_DATAPULSE( rtl_addr, EEPROM_PG_ON | EEPROM_PG_EECS );
+    EEPROM_WR_DATAPULSE( rtl_addr, EEPROM_PG_ON | EEPROM_PG_EECS );
+    EEPROM_WR_DATAPULSE( rtl_addr, EEPROM_PG_ON | EEPROM_PG_EECS );
+    EEPROM_WR_DATAPULSE( rtl_addr, EEPROM_PG_ON | EEPROM_PG_EECS );
+    EEPROM_WR_DATAPULSE( rtl_addr, EEPROM_PG_ON );
+
+    // set command
+    mask_bit8 = 0x04;
+    for(icount = 0; icount < 3; icount++){
+        EEPROM_WR_DATAPULSE( rtl_addr, EEPROM_PG_ON | EEPROM_PG_EECS | EEPROM_MASK( mask_bit8, eeprom_cmd ));
+        mask_bit8 >>= 1;
+    }
+
+    // set address
+    mask_bit8 = 0x20;
+    for(icount = 0; icount < 6; icount++){
+        EEPROM_WR_DATAPULSE( rtl_addr, EEPROM_PG_ON | EEPROM_PG_EECS | EEPROM_MASK( mask_bit8, eeprom_addr ));
+        mask_bit8 >>= 1;
+    }
+
+    // set data
+    mask_bit16 = 0x8000;
+    for(icount = 0; icount < 16; icount++){
+        EEPROM_WR_DATAPULSE( rtl_addr, EEPROM_PG_ON | EEPROM_PG_EECS | EEPROM_MASK( mask_bit16, src_data ));
+        mask_bit16 >>= 1;
+    }
+
+    // close
+    EEPROM_WR_DATA( rtl_addr, EEPROM_PG_ON );
+    EEPROM_WR_DATA( rtl_addr, EEPROM_PG_ON | EEPROM_PG_EESK );
+    EEPROM_WR_DATA( rtl_addr, EEPROM_PG_ON );
+
+    // write ready check
+    EEPROM_WR_DATA( rtl_addr, EEPROM_PG_ON | EEPROM_PG_EECS );
+
+    // wait busy disable
+    icount = 0;
+    while( 1 ){
+        cyg_thread_delay( 1 );
+        HAL_WRITE_UINT8( rtl_addr, EEPROM_PG_ON | EEPROM_PG_EECS | EEPROM_PG_EESK );
+        HAL_WRITE_UINT8( rtl_addr, EEPROM_PG_ON | EEPROM_PG_EECS );
+        HAL_READ_UINT8( rtl_addr, read_data );
+        if(( read_data & EEPROM_PG_EEDO ) != 0 ){
+            break;
+        }
+        if( icount++ >= EEPROM_WR_BUSY_RETRIES ){
+            diag_printf("EEPROM write wait error adr=0x%02x data=0x%04x\n", eeprom_addr, src_data );
+            break;
+        }
+    }
+    HAL_WRITE_UINT8( rtl_addr, EEPROM_PG_ON );
+
+    // put old parameter
+    HAL_WRITE_UINT8( rtl_addr, org_param );
+}
+
+#endif