rtl8029.c

Go to the documentation of this file.
00001 /*
00002 rtl8029.c
00003 
00004 Initialization of PCI DP8390-based ethernet cards
00005 
00006 Created:        April 2000 by Philip Homburg <philip@f-mnx.phicoh.com>
00007 */
00008 
00009 #include "../drivers.h"
00010 
00011 #include <stdlib.h>
00012 #include <sys/types.h>
00013 #include <net/gen/ether.h>
00014 #include <net/gen/eth_io.h>
00015 #include <ibm/pci.h>
00016 
00017 #include "assert.h"
00018 
00019 #include "local.h"
00020 #include "dp8390.h"
00021 #include "rtl8029.h"
00022 
00023 #if ENABLE_PCI
00024 
00025 #define MICROS_TO_TICKS(m)  (((m)*HZ/1000000)+1)
00026 
00027 PRIVATE struct pcitab
00028 {
00029         u16_t vid;
00030         u16_t did;
00031         int checkclass;
00032 } pcitab[]=
00033 {
00034         { 0x10ec, 0x8029, 0 },          /* Realtek RTL8029 */
00035 
00036         { 0x0000, 0x0000, 0 }
00037 };
00038 
00039 _PROTOTYPE( static void rtl_init, (struct dpeth *dep)                   );
00040 _PROTOTYPE( static u16_t get_ee_word, (dpeth_t *dep, int a)             );
00041 _PROTOTYPE( static void ee_wen, (dpeth_t *dep)                          );
00042 _PROTOTYPE( static void set_ee_word, (dpeth_t *dep, int a, U16_t w)     );
00043 _PROTOTYPE( static void ee_wds, (dpeth_t *dep)                          );
00044 _PROTOTYPE( static void micro_delay, (unsigned long usecs)              );
00045 
00046 PUBLIC int rtl_probe(dep)
00047 struct dpeth *dep;
00048 {
00049         int i, r, devind, just_one;
00050         u16_t vid, did;
00051         u32_t bar;
00052         u8_t ilr;
00053         char *dname;
00054 
00055         pci_init();
00056 
00057         if ((dep->de_pcibus | dep->de_pcidev | dep->de_pcifunc) != 0)
00058         {
00059                 /* Look for specific PCI device */
00060                 r= pci_find_dev(dep->de_pcibus, dep->de_pcidev,
00061                         dep->de_pcifunc, &devind);
00062                 if (r == 0)
00063                 {
00064                         printf("%s: no PCI found at %d.%d.%d\n",
00065                                 dep->de_name, dep->de_pcibus,
00066                                 dep->de_pcidev, dep->de_pcifunc);
00067                         return 0;
00068                 }
00069                 pci_ids(devind, &vid, &did);
00070                 just_one= TRUE;
00071         }
00072         else
00073         {
00074                 r= pci_first_dev(&devind, &vid, &did);
00075                 if (r == 0)
00076                         return 0;
00077                 just_one= FALSE;
00078         }
00079 
00080         for(;;)
00081         {
00082                 for (i= 0; pcitab[i].vid != 0; i++)
00083                 {
00084                         if (pcitab[i].vid != vid)
00085                                 continue;
00086                         if (pcitab[i].did != did)
00087                                 continue;
00088                         if (pcitab[i].checkclass)
00089                         {
00090                                 panic("",
00091                                 "rtl_probe: class check not implemented",
00092                                         NO_NUM);
00093                         }
00094                         break;
00095                 }
00096                 if (pcitab[i].vid != 0)
00097                         break;
00098 
00099                 if (just_one)
00100                 {
00101                         printf(
00102                 "%s: wrong PCI device (%04X/%04X) found at %d.%d.%d\n",
00103                                 dep->de_name, vid, did,
00104                                 dep->de_pcibus,
00105                                 dep->de_pcidev, dep->de_pcifunc);
00106                         return 0;
00107                 }
00108 
00109                 r= pci_next_dev(&devind, &vid, &did);
00110                 if (!r)
00111                         return 0;
00112         }
00113 
00114         dname= pci_dev_name(vid, did);
00115         if (!dname)
00116                 dname= "unknown device";
00117         printf("%s: %s (%04X/%04X) at %s\n",
00118                 dep->de_name, dname, vid, did, pci_slot_name(devind));
00119         pci_reserve(devind);
00120         /* printf("cr = 0x%x\n", pci_attr_r16(devind, PCI_CR)); */
00121         bar= pci_attr_r32(devind, PCI_BAR) & 0xffffffe0;
00122 
00123         if (bar < 0x400)
00124                 panic("", "base address is not properly configured", NO_NUM);
00125 
00126         dep->de_base_port= bar;
00127 
00128         ilr= pci_attr_r8(devind, PCI_ILR);
00129         dep->de_irq= ilr;
00130         if (debug)
00131         {
00132                 printf("%s: using I/O address 0x%lx, IRQ %d\n",
00133                         dep->de_name, (unsigned long)bar, ilr);
00134         }
00135         dep->de_initf= rtl_init;
00136 
00137         return TRUE;
00138 }
00139 
00140 static void rtl_init(dep)
00141 dpeth_t *dep;
00142 {
00143         u8_t reg_a, reg_b, cr, config0, config2, config3;
00144         int i;
00145 
00146 #if DEBUG
00147         printf("rtl_init called\n");
00148 #endif
00149         ne_init(dep);
00150 
00151         /* ID */
00152         outb_reg0(dep, DP_CR, CR_PS_P0);
00153         reg_a = inb_reg0(dep, DP_DUM1);
00154         reg_b = inb_reg0(dep, DP_DUM2);
00155 
00156 #if DEBUG
00157         printf("rtl_init: '%c', '%c'\n", reg_a, reg_b);
00158 #endif
00159 
00160         outb_reg0(dep, DP_CR, CR_PS_P3);
00161         config0 = inb_reg3(dep, 3);
00162         config2 = inb_reg3(dep, 5);
00163         config3 = inb_reg3(dep, 6);
00164         outb_reg0(dep, DP_CR, CR_PS_P0);
00165 
00166 #if DEBUG
00167         printf("rtl_init: config 0/2/3 = %x/%x/%x\n",
00168                 config0, config2, config3);
00169 #endif
00170 
00171         if (getenv("RTL8029FD"))
00172         {
00173                 printf("rtl_init: setting full-duplex mode\n");
00174                 outb_reg0(dep, DP_CR, CR_PS_P3);
00175 
00176                 cr= inb_reg3(dep, 1);
00177                 outb_reg3(dep, 1, cr | 0xc0);
00178 
00179                 outb_reg3(dep, 6, config3 | 0x40);
00180                 config3 = inb_reg3(dep, 6);
00181 
00182                 config2= inb_reg3(dep, 5);
00183                 outb_reg3(dep, 5, config2 | 0x20);
00184                 config2= inb_reg3(dep, 5);
00185 
00186                 outb_reg3(dep, 1, cr);
00187 
00188                 outb_reg0(dep, DP_CR, CR_PS_P0);
00189 
00190 #if DEBUG
00191                 printf("rtl_init: config 2 = %x\n", config2);
00192                 printf("rtl_init: config 3 = %x\n", config3);
00193 #endif
00194         }
00195 
00196 #if DEBUG
00197         for (i= 0; i<64; i++)
00198                 printf("%x ", get_ee_word(dep, i));
00199         printf("\n");
00200 #endif
00201 
00202         if (getenv("RTL8029MN"))
00203         {
00204                 ee_wen(dep);
00205 
00206                 set_ee_word(dep, 0x78/2, 0x10ec);
00207                 set_ee_word(dep, 0x7A/2, 0x8029);
00208                 set_ee_word(dep, 0x7C/2, 0x10ec);
00209                 set_ee_word(dep, 0x7E/2, 0x8029);
00210 
00211                 ee_wds(dep);
00212 
00213                 assert(get_ee_word(dep, 0x78/2) == 0x10ec);
00214                 assert(get_ee_word(dep, 0x7A/2) == 0x8029);
00215                 assert(get_ee_word(dep, 0x7C/2) == 0x10ec);
00216                 assert(get_ee_word(dep, 0x7E/2) == 0x8029);
00217         }
00218 
00219         if (getenv("RTL8029XXX"))
00220         {
00221                 ee_wen(dep);
00222 
00223                 set_ee_word(dep, 0x76/2, 0x8029);
00224 
00225                 ee_wds(dep);
00226 
00227                 assert(get_ee_word(dep, 0x76/2) == 0x8029);
00228         }
00229 }
00230 
00231 static u16_t get_ee_word(dep, a)
00232 dpeth_t *dep;
00233 int a;
00234 {
00235         int b, i, cmd;
00236         u16_t w;
00237 
00238         outb_reg0(dep, DP_CR, CR_PS_P3);        /* Bank 3 */
00239 
00240         /* Switch to 9346 mode and enable CS */
00241         outb_reg3(dep, 1, 0x80 | 0x8);
00242 
00243         cmd= 0x180 | (a & 0x3f);        /* 1 1 0 a5 a4 a3 a2 a1 a0 */
00244         for (i= 8; i >= 0; i--)
00245         {
00246                 b= (cmd & (1 << i));
00247                 b= (b ? 2 : 0);
00248 
00249                 /* Cmd goes out on the rising edge of the clock */
00250                 outb_reg3(dep, 1, 0x80 | 0x8 | b);
00251                 outb_reg3(dep, 1, 0x80 | 0x8 | 0x4 | b);
00252         }
00253         outb_reg3(dep, 1, 0x80 | 0x8);  /* End of cmd */
00254 
00255         w= 0;
00256         for (i= 0; i<16; i++)
00257         {
00258                 w <<= 1;
00259 
00260                 /* Data is shifted out on the rising edge. Read at the
00261                  * falling edge.
00262                  */
00263                 outb_reg3(dep, 1, 0x80 | 0x8 | 0x4);
00264                 outb_reg3(dep, 1, 0x80 | 0x8 | b);
00265                 b= inb_reg3(dep, 1);
00266                 w |= (b & 1);
00267         }
00268 
00269         outb_reg3(dep, 1, 0x80);                /* drop CS */
00270         outb_reg3(dep, 1, 0x00);                /* back to normal */
00271         outb_reg0(dep, DP_CR, CR_PS_P0);        /* back to bank 0 */
00272 
00273         return w;
00274 }
00275 
00276 static void ee_wen(dep)
00277 dpeth_t *dep;
00278 {
00279         int b, i, cmd;
00280 
00281         outb_reg0(dep, DP_CR, CR_PS_P3);        /* Bank 3 */
00282 
00283         /* Switch to 9346 mode and enable CS */
00284         outb_reg3(dep, 1, 0x80 | 0x8);
00285 
00286         cmd= 0x130;             /* 1 0 0 1 1 x x x x */
00287         for (i= 8; i >= 0; i--)
00288         {
00289                 b= (cmd & (1 << i));
00290                 b= (b ? 2 : 0);
00291 
00292                 /* Cmd goes out on the rising edge of the clock */
00293                 outb_reg3(dep, 1, 0x80 | 0x8 | b);
00294                 outb_reg3(dep, 1, 0x80 | 0x8 | 0x4 | b);
00295         }
00296         outb_reg3(dep, 1, 0x80 | 0x8);  /* End of cmd */
00297         outb_reg3(dep, 1, 0x80);        /* Drop CS */
00298         micro_delay(1);                 /* Is this required? */
00299 }
00300 
00301 static void set_ee_word(dep, a, w)
00302 dpeth_t *dep;
00303 int a;
00304 u16_t w;
00305 {
00306         int b, i, cmd;
00307 
00308         outb_reg3(dep, 1, 0x80 | 0x8);          /* Set CS */
00309 
00310         cmd= 0x140 | (a & 0x3f);                /* 1 0 1 a5 a4 a3 a2 a1 a0 */
00311         for (i= 8; i >= 0; i--)
00312         {
00313                 b= (cmd & (1 << i));
00314                 b= (b ? 2 : 0);
00315 
00316                 /* Cmd goes out on the rising edge of the clock */
00317                 outb_reg3(dep, 1, 0x80 | 0x8 | b);
00318                 outb_reg3(dep, 1, 0x80 | 0x8 | 0x4 | b);
00319         }
00320         for (i= 15; i >= 0; i--)
00321         {
00322                 b= (w & (1 << i));
00323                 b= (b ? 2 : 0);
00324 
00325                 /* Cmd goes out on the rising edge of the clock */
00326                 outb_reg3(dep, 1, 0x80 | 0x8 | b);
00327                 outb_reg3(dep, 1, 0x80 | 0x8 | 0x4 | b);
00328         }
00329         outb_reg3(dep, 1, 0x80 | 0x8);  /* End of data */
00330         outb_reg3(dep, 1, 0x80);        /* Drop CS */
00331         micro_delay(1);                 /* Is this required? */
00332         outb_reg3(dep, 1, 0x80 | 0x8);          /* Set CS */
00333         for (i= 0; i<10000; i++)
00334         {
00335                 if (inb_reg3(dep, 1) & 1)
00336                         break;
00337                 micro_delay(1);
00338         }
00339         if (!(inb_reg3(dep, 1) & 1))
00340                 panic("", "set_ee_word: device remains busy", NO_NUM);
00341 }
00342 
00343 static void ee_wds(dep)
00344 dpeth_t *dep;
00345 {
00346         int b, i, cmd;
00347 
00348         outb_reg0(dep, DP_CR, CR_PS_P3);        /* Bank 3 */
00349 
00350         /* Switch to 9346 mode and enable CS */
00351         outb_reg3(dep, 1, 0x80 | 0x8);
00352 
00353         cmd= 0x100;             /* 1 0 0 0 0 x x x x */
00354         for (i= 8; i >= 0; i--)
00355         {
00356                 b= (cmd & (1 << i));
00357                 b= (b ? 2 : 0);
00358 
00359                 /* Cmd goes out on the rising edge of the clock */
00360                 outb_reg3(dep, 1, 0x80 | 0x8 | b);
00361                 outb_reg3(dep, 1, 0x80 | 0x8 | 0x4 | b);
00362         }
00363         outb_reg3(dep, 1, 0x80 | 0x8);  /* End of cmd */
00364         outb_reg3(dep, 1, 0x80);        /* Drop CS */
00365         outb_reg3(dep, 1, 0x00);                /* back to normal */
00366         outb_reg0(dep, DP_CR, CR_PS_P0);        /* back to bank 0 */
00367 }
00368 
00369 static void micro_delay(unsigned long usecs)
00370 {
00371         tickdelay(MICROS_TO_TICKS(usecs));
00372 }
00373 
00374 #endif /* ENABLE_PCI */
00375 
00376 /*
00377  * $PchId: rtl8029.c,v 1.7 2004/08/03 12:16:58 philip Exp $
00378  */

Generated on Fri Apr 14 22:57:15 2006 for minix by  doxygen 1.4.6