00001
00002
00003
00004
00005
00006
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 },
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
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
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
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);
00239
00240
00241 outb_reg3(dep, 1, 0x80 | 0x8);
00242
00243 cmd= 0x180 | (a & 0x3f);
00244 for (i= 8; i >= 0; i--)
00245 {
00246 b= (cmd & (1 << i));
00247 b= (b ? 2 : 0);
00248
00249
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);
00254
00255 w= 0;
00256 for (i= 0; i<16; i++)
00257 {
00258 w <<= 1;
00259
00260
00261
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);
00270 outb_reg3(dep, 1, 0x00);
00271 outb_reg0(dep, DP_CR, CR_PS_P0);
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);
00282
00283
00284 outb_reg3(dep, 1, 0x80 | 0x8);
00285
00286 cmd= 0x130;
00287 for (i= 8; i >= 0; i--)
00288 {
00289 b= (cmd & (1 << i));
00290 b= (b ? 2 : 0);
00291
00292
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);
00297 outb_reg3(dep, 1, 0x80);
00298 micro_delay(1);
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);
00309
00310 cmd= 0x140 | (a & 0x3f);
00311 for (i= 8; i >= 0; i--)
00312 {
00313 b= (cmd & (1 << i));
00314 b= (b ? 2 : 0);
00315
00316
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
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);
00330 outb_reg3(dep, 1, 0x80);
00331 micro_delay(1);
00332 outb_reg3(dep, 1, 0x80 | 0x8);
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);
00349
00350
00351 outb_reg3(dep, 1, 0x80 | 0x8);
00352
00353 cmd= 0x100;
00354 for (i= 8; i >= 0; i--)
00355 {
00356 b= (cmd & (1 << i));
00357 b= (b ? 2 : 0);
00358
00359
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);
00364 outb_reg3(dep, 1, 0x80);
00365 outb_reg3(dep, 1, 0x00);
00366 outb_reg0(dep, DP_CR, CR_PS_P0);
00367 }
00368
00369 static void micro_delay(unsigned long usecs)
00370 {
00371 tickdelay(MICROS_TO_TICKS(usecs));
00372 }
00373
00374 #endif
00375
00376
00377
00378