1 /* 2 rtl8029.c 3 4 Initialization of PCI DP8390-based ethernet cards 5 6 Created: April 2000 by Philip Homburg <philip@f-mnx.phicoh.com> 7 */ 8 9 #include <minix/drivers.h> 10 #include <minix/netdriver.h> 11 12 #include <stdlib.h> 13 #include <sys/types.h> 14 #include <net/gen/ether.h> 15 #include <net/gen/eth_io.h> 16 #include <machine/pci.h> 17 18 #include "assert.h" 19 20 #include "local.h" 21 #include "dp8390.h" 22 #include "rtl8029.h" 23 24 static void rtl_init(struct dpeth *dep); 25 #if 0 26 static u16_t get_ee_word(dpeth_t *dep, int a); 27 static void ee_wen(dpeth_t *dep); 28 static void set_ee_word(dpeth_t *dep, int a, u16_t w); 29 static void ee_wds(dpeth_t *dep); 30 #endif 31 32 int rtl_probe(dep, skip) 33 struct dpeth *dep; 34 int skip; 35 { 36 int r, devind; 37 u16_t vid, did; 38 u32_t bar; 39 u8_t ilr; 40 char *dname; 41 42 pci_init(); 43 44 r= pci_first_dev(&devind, &vid, &did); 45 if (r == 0) 46 return 0; 47 48 while (skip--) 49 { 50 r= pci_next_dev(&devind, &vid, &did); 51 if (!r) 52 return 0; 53 } 54 55 dname= pci_dev_name(vid, did); 56 if (!dname) 57 dname= "unknown device"; 58 printf("%s: %s (%04X/%04X) at %s\n", 59 dep->de_name, dname, vid, did, pci_slot_name(devind)); 60 if(pci_reserve_ok(devind) != OK) 61 return 0; 62 /* printf("cr = 0x%x\n", pci_attr_r16(devind, PCI_CR)); */ 63 bar= pci_attr_r32(devind, PCI_BAR) & 0xffffffe0; 64 65 if (bar < 0x400) 66 panic("base address is not properly configured"); 67 68 dep->de_base_port= bar; 69 70 ilr= pci_attr_r8(devind, PCI_ILR); 71 dep->de_irq= ilr; 72 if (debug) 73 { 74 printf("%s: using I/O address 0x%lx, IRQ %d\n", 75 dep->de_name, (unsigned long)bar, ilr); 76 } 77 dep->de_initf= rtl_init; 78 79 return TRUE; 80 } 81 82 static void rtl_init(dep) 83 dpeth_t *dep; 84 { 85 u8_t reg_a, reg_b, cr, config0, config2, config3; 86 87 #if DEBUG 88 printf("rtl_init called\n"); 89 #endif 90 ne_init(dep); 91 92 /* ID */ 93 outb_reg0(dep, DP_CR, CR_PS_P0); 94 reg_a = inb_reg0(dep, DP_DUM1); 95 reg_b = inb_reg0(dep, DP_DUM2); 96 97 #if DEBUG 98 printf("rtl_init: '%c', '%c'\n", reg_a, reg_b); 99 #endif 100 101 outb_reg0(dep, DP_CR, CR_PS_P3); 102 config0 = inb_reg3(dep, 3); 103 config2 = inb_reg3(dep, 5); 104 config3 = inb_reg3(dep, 6); 105 outb_reg0(dep, DP_CR, CR_PS_P0); 106 107 #if DEBUG 108 printf("rtl_init: config 0/2/3 = %x/%x/%x\n", 109 config0, config2, config3); 110 #endif 111 112 if (getenv("RTL8029FD")) 113 { 114 printf("rtl_init: setting full-duplex mode\n"); 115 outb_reg0(dep, DP_CR, CR_PS_P3); 116 117 cr= inb_reg3(dep, 1); 118 outb_reg3(dep, 1, cr | 0xc0); 119 120 outb_reg3(dep, 6, config3 | 0x40); 121 config3 = inb_reg3(dep, 6); 122 123 config2= inb_reg3(dep, 5); 124 outb_reg3(dep, 5, config2 | 0x20); 125 config2= inb_reg3(dep, 5); 126 127 outb_reg3(dep, 1, cr); 128 129 outb_reg0(dep, DP_CR, CR_PS_P0); 130 131 #if DEBUG 132 printf("rtl_init: config 2 = %x\n", config2); 133 printf("rtl_init: config 3 = %x\n", config3); 134 #endif 135 } 136 137 #if 0 138 for (i= 0; i<64; i++) 139 printf("%x ", get_ee_word(dep, i)); 140 printf("\n"); 141 #endif 142 143 #if 0 144 if (getenv("RTL8029MN")) 145 { 146 ee_wen(dep); 147 148 set_ee_word(dep, 0x78/2, 0x10ec); 149 set_ee_word(dep, 0x7A/2, 0x8029); 150 set_ee_word(dep, 0x7C/2, 0x10ec); 151 set_ee_word(dep, 0x7E/2, 0x8029); 152 153 ee_wds(dep); 154 155 assert(get_ee_word(dep, 0x78/2) == 0x10ec); 156 assert(get_ee_word(dep, 0x7A/2) == 0x8029); 157 assert(get_ee_word(dep, 0x7C/2) == 0x10ec); 158 assert(get_ee_word(dep, 0x7E/2) == 0x8029); 159 } 160 161 if (getenv("RTL8029XXX")) 162 { 163 ee_wen(dep); 164 165 set_ee_word(dep, 0x76/2, 0x8029); 166 167 ee_wds(dep); 168 169 assert(get_ee_word(dep, 0x76/2) == 0x8029); 170 } 171 #endif 172 } 173 174 #if 0 175 static u16_t get_ee_word(dep, a) 176 dpeth_t *dep; 177 int a; 178 { 179 int b, i, cmd; 180 u16_t w; 181 182 outb_reg0(dep, DP_CR, CR_PS_P3); /* Bank 3 */ 183 184 /* Switch to 9346 mode and enable CS */ 185 outb_reg3(dep, 1, 0x80 | 0x8); 186 187 cmd= 0x180 | (a & 0x3f); /* 1 1 0 a5 a4 a3 a2 a1 a0 */ 188 for (i= 8; i >= 0; i--) 189 { 190 b= (cmd & (1 << i)); 191 b= (b ? 2 : 0); 192 193 /* Cmd goes out on the rising edge of the clock */ 194 outb_reg3(dep, 1, 0x80 | 0x8 | b); 195 outb_reg3(dep, 1, 0x80 | 0x8 | 0x4 | b); 196 } 197 outb_reg3(dep, 1, 0x80 | 0x8); /* End of cmd */ 198 199 w= 0; 200 for (i= 0; i<16; i++) 201 { 202 w <<= 1; 203 204 /* Data is shifted out on the rising edge. Read at the 205 * falling edge. 206 */ 207 outb_reg3(dep, 1, 0x80 | 0x8 | 0x4); 208 outb_reg3(dep, 1, 0x80 | 0x8 | b); 209 b= inb_reg3(dep, 1); 210 w |= (b & 1); 211 } 212 213 outb_reg3(dep, 1, 0x80); /* drop CS */ 214 outb_reg3(dep, 1, 0x00); /* back to normal */ 215 outb_reg0(dep, DP_CR, CR_PS_P0); /* back to bank 0 */ 216 217 return w; 218 } 219 220 static void ee_wen(dep) 221 dpeth_t *dep; 222 { 223 int b, i, cmd; 224 225 outb_reg0(dep, DP_CR, CR_PS_P3); /* Bank 3 */ 226 227 /* Switch to 9346 mode and enable CS */ 228 outb_reg3(dep, 1, 0x80 | 0x8); 229 230 cmd= 0x130; /* 1 0 0 1 1 x x x x */ 231 for (i= 8; i >= 0; i--) 232 { 233 b= (cmd & (1 << i)); 234 b= (b ? 2 : 0); 235 236 /* Cmd goes out on the rising edge of the clock */ 237 outb_reg3(dep, 1, 0x80 | 0x8 | b); 238 outb_reg3(dep, 1, 0x80 | 0x8 | 0x4 | b); 239 } 240 outb_reg3(dep, 1, 0x80 | 0x8); /* End of cmd */ 241 outb_reg3(dep, 1, 0x80); /* Drop CS */ 242 micro_delay(1); /* Is this required? */ 243 } 244 245 static void set_ee_word(dep, a, w) 246 dpeth_t *dep; 247 int a; 248 u16_t w; 249 { 250 int b, i, cmd; 251 252 outb_reg3(dep, 1, 0x80 | 0x8); /* Set CS */ 253 254 cmd= 0x140 | (a & 0x3f); /* 1 0 1 a5 a4 a3 a2 a1 a0 */ 255 for (i= 8; i >= 0; i--) 256 { 257 b= (cmd & (1 << i)); 258 b= (b ? 2 : 0); 259 260 /* Cmd goes out on the rising edge of the clock */ 261 outb_reg3(dep, 1, 0x80 | 0x8 | b); 262 outb_reg3(dep, 1, 0x80 | 0x8 | 0x4 | b); 263 } 264 for (i= 15; i >= 0; i--) 265 { 266 b= (w & (1 << i)); 267 b= (b ? 2 : 0); 268 269 /* Cmd goes out on the rising edge of the clock */ 270 outb_reg3(dep, 1, 0x80 | 0x8 | b); 271 outb_reg3(dep, 1, 0x80 | 0x8 | 0x4 | b); 272 } 273 outb_reg3(dep, 1, 0x80 | 0x8); /* End of data */ 274 outb_reg3(dep, 1, 0x80); /* Drop CS */ 275 micro_delay(1); /* Is this required? */ 276 outb_reg3(dep, 1, 0x80 | 0x8); /* Set CS */ 277 for (i= 0; i<10000; i++) 278 { 279 if (inb_reg3(dep, 1) & 1) 280 break; 281 micro_delay(1); 282 } 283 if (!(inb_reg3(dep, 1) & 1)) 284 panic("set_ee_word: device remains busy"); 285 } 286 287 static void ee_wds(dep) 288 dpeth_t *dep; 289 { 290 int b, i, cmd; 291 292 outb_reg0(dep, DP_CR, CR_PS_P3); /* Bank 3 */ 293 294 /* Switch to 9346 mode and enable CS */ 295 outb_reg3(dep, 1, 0x80 | 0x8); 296 297 cmd= 0x100; /* 1 0 0 0 0 x x x x */ 298 for (i= 8; i >= 0; i--) 299 { 300 b= (cmd & (1 << i)); 301 b= (b ? 2 : 0); 302 303 /* Cmd goes out on the rising edge of the clock */ 304 outb_reg3(dep, 1, 0x80 | 0x8 | b); 305 outb_reg3(dep, 1, 0x80 | 0x8 | 0x4 | b); 306 } 307 outb_reg3(dep, 1, 0x80 | 0x8); /* End of cmd */ 308 outb_reg3(dep, 1, 0x80); /* Drop CS */ 309 outb_reg3(dep, 1, 0x00); /* back to normal */ 310 outb_reg0(dep, DP_CR, CR_PS_P0); /* back to bank 0 */ 311 } 312 #endif 313 314 /* 315 * $PchId: rtl8029.c,v 1.7 2004/08/03 12:16:58 philip Exp $ 316 */ 317