1433d6423SLionel Sambuc /* 2433d6423SLionel Sambuc rtl8029.c 3433d6423SLionel Sambuc 4433d6423SLionel Sambuc Initialization of PCI DP8390-based ethernet cards 5433d6423SLionel Sambuc 6433d6423SLionel Sambuc Created: April 2000 by Philip Homburg <philip@f-mnx.phicoh.com> 7433d6423SLionel Sambuc */ 8433d6423SLionel Sambuc 9433d6423SLionel Sambuc #include <minix/drivers.h> 10*3913e490SDavid van Moolenbroek #include <minix/netdriver.h> 11433d6423SLionel Sambuc 12433d6423SLionel Sambuc #include <stdlib.h> 13433d6423SLionel Sambuc #include <sys/types.h> 14433d6423SLionel Sambuc #include <net/gen/ether.h> 15433d6423SLionel Sambuc #include <net/gen/eth_io.h> 16433d6423SLionel Sambuc #include <machine/pci.h> 17433d6423SLionel Sambuc 18433d6423SLionel Sambuc #include "assert.h" 19433d6423SLionel Sambuc 20433d6423SLionel Sambuc #include "local.h" 21433d6423SLionel Sambuc #include "dp8390.h" 22433d6423SLionel Sambuc #include "rtl8029.h" 23433d6423SLionel Sambuc 24433d6423SLionel Sambuc static void rtl_init(struct dpeth *dep); 25433d6423SLionel Sambuc #if 0 26433d6423SLionel Sambuc static u16_t get_ee_word(dpeth_t *dep, int a); 27433d6423SLionel Sambuc static void ee_wen(dpeth_t *dep); 28433d6423SLionel Sambuc static void set_ee_word(dpeth_t *dep, int a, u16_t w); 29433d6423SLionel Sambuc static void ee_wds(dpeth_t *dep); 30433d6423SLionel Sambuc #endif 31433d6423SLionel Sambuc 32433d6423SLionel Sambuc int rtl_probe(dep, skip) 33433d6423SLionel Sambuc struct dpeth *dep; 34433d6423SLionel Sambuc int skip; 35433d6423SLionel Sambuc { 36433d6423SLionel Sambuc int r, devind; 37433d6423SLionel Sambuc u16_t vid, did; 38433d6423SLionel Sambuc u32_t bar; 39433d6423SLionel Sambuc u8_t ilr; 40433d6423SLionel Sambuc char *dname; 41433d6423SLionel Sambuc 42433d6423SLionel Sambuc pci_init(); 43433d6423SLionel Sambuc 44433d6423SLionel Sambuc r= pci_first_dev(&devind, &vid, &did); 45433d6423SLionel Sambuc if (r == 0) 46433d6423SLionel Sambuc return 0; 47433d6423SLionel Sambuc 48433d6423SLionel Sambuc while (skip--) 49433d6423SLionel Sambuc { 50433d6423SLionel Sambuc r= pci_next_dev(&devind, &vid, &did); 51433d6423SLionel Sambuc if (!r) 52433d6423SLionel Sambuc return 0; 53433d6423SLionel Sambuc } 54433d6423SLionel Sambuc 55433d6423SLionel Sambuc dname= pci_dev_name(vid, did); 56433d6423SLionel Sambuc if (!dname) 57433d6423SLionel Sambuc dname= "unknown device"; 58433d6423SLionel Sambuc printf("%s: %s (%04X/%04X) at %s\n", 59433d6423SLionel Sambuc dep->de_name, dname, vid, did, pci_slot_name(devind)); 60433d6423SLionel Sambuc if(pci_reserve_ok(devind) != OK) 61433d6423SLionel Sambuc return 0; 62433d6423SLionel Sambuc /* printf("cr = 0x%x\n", pci_attr_r16(devind, PCI_CR)); */ 63433d6423SLionel Sambuc bar= pci_attr_r32(devind, PCI_BAR) & 0xffffffe0; 64433d6423SLionel Sambuc 65433d6423SLionel Sambuc if (bar < 0x400) 66433d6423SLionel Sambuc panic("base address is not properly configured"); 67433d6423SLionel Sambuc 68433d6423SLionel Sambuc dep->de_base_port= bar; 69433d6423SLionel Sambuc 70433d6423SLionel Sambuc ilr= pci_attr_r8(devind, PCI_ILR); 71433d6423SLionel Sambuc dep->de_irq= ilr; 72433d6423SLionel Sambuc if (debug) 73433d6423SLionel Sambuc { 74433d6423SLionel Sambuc printf("%s: using I/O address 0x%lx, IRQ %d\n", 75433d6423SLionel Sambuc dep->de_name, (unsigned long)bar, ilr); 76433d6423SLionel Sambuc } 77433d6423SLionel Sambuc dep->de_initf= rtl_init; 78433d6423SLionel Sambuc 79433d6423SLionel Sambuc return TRUE; 80433d6423SLionel Sambuc } 81433d6423SLionel Sambuc 82433d6423SLionel Sambuc static void rtl_init(dep) 83433d6423SLionel Sambuc dpeth_t *dep; 84433d6423SLionel Sambuc { 85433d6423SLionel Sambuc u8_t reg_a, reg_b, cr, config0, config2, config3; 86433d6423SLionel Sambuc 87433d6423SLionel Sambuc #if DEBUG 88433d6423SLionel Sambuc printf("rtl_init called\n"); 89433d6423SLionel Sambuc #endif 90433d6423SLionel Sambuc ne_init(dep); 91433d6423SLionel Sambuc 92433d6423SLionel Sambuc /* ID */ 93433d6423SLionel Sambuc outb_reg0(dep, DP_CR, CR_PS_P0); 94433d6423SLionel Sambuc reg_a = inb_reg0(dep, DP_DUM1); 95433d6423SLionel Sambuc reg_b = inb_reg0(dep, DP_DUM2); 96433d6423SLionel Sambuc 97433d6423SLionel Sambuc #if DEBUG 98433d6423SLionel Sambuc printf("rtl_init: '%c', '%c'\n", reg_a, reg_b); 99433d6423SLionel Sambuc #endif 100433d6423SLionel Sambuc 101433d6423SLionel Sambuc outb_reg0(dep, DP_CR, CR_PS_P3); 102433d6423SLionel Sambuc config0 = inb_reg3(dep, 3); 103433d6423SLionel Sambuc config2 = inb_reg3(dep, 5); 104433d6423SLionel Sambuc config3 = inb_reg3(dep, 6); 105433d6423SLionel Sambuc outb_reg0(dep, DP_CR, CR_PS_P0); 106433d6423SLionel Sambuc 107433d6423SLionel Sambuc #if DEBUG 108433d6423SLionel Sambuc printf("rtl_init: config 0/2/3 = %x/%x/%x\n", 109433d6423SLionel Sambuc config0, config2, config3); 110433d6423SLionel Sambuc #endif 111433d6423SLionel Sambuc 112433d6423SLionel Sambuc if (getenv("RTL8029FD")) 113433d6423SLionel Sambuc { 114433d6423SLionel Sambuc printf("rtl_init: setting full-duplex mode\n"); 115433d6423SLionel Sambuc outb_reg0(dep, DP_CR, CR_PS_P3); 116433d6423SLionel Sambuc 117433d6423SLionel Sambuc cr= inb_reg3(dep, 1); 118433d6423SLionel Sambuc outb_reg3(dep, 1, cr | 0xc0); 119433d6423SLionel Sambuc 120433d6423SLionel Sambuc outb_reg3(dep, 6, config3 | 0x40); 121433d6423SLionel Sambuc config3 = inb_reg3(dep, 6); 122433d6423SLionel Sambuc 123433d6423SLionel Sambuc config2= inb_reg3(dep, 5); 124433d6423SLionel Sambuc outb_reg3(dep, 5, config2 | 0x20); 125433d6423SLionel Sambuc config2= inb_reg3(dep, 5); 126433d6423SLionel Sambuc 127433d6423SLionel Sambuc outb_reg3(dep, 1, cr); 128433d6423SLionel Sambuc 129433d6423SLionel Sambuc outb_reg0(dep, DP_CR, CR_PS_P0); 130433d6423SLionel Sambuc 131433d6423SLionel Sambuc #if DEBUG 132433d6423SLionel Sambuc printf("rtl_init: config 2 = %x\n", config2); 133433d6423SLionel Sambuc printf("rtl_init: config 3 = %x\n", config3); 134433d6423SLionel Sambuc #endif 135433d6423SLionel Sambuc } 136433d6423SLionel Sambuc 137433d6423SLionel Sambuc #if 0 138433d6423SLionel Sambuc for (i= 0; i<64; i++) 139433d6423SLionel Sambuc printf("%x ", get_ee_word(dep, i)); 140433d6423SLionel Sambuc printf("\n"); 141433d6423SLionel Sambuc #endif 142433d6423SLionel Sambuc 143433d6423SLionel Sambuc #if 0 144433d6423SLionel Sambuc if (getenv("RTL8029MN")) 145433d6423SLionel Sambuc { 146433d6423SLionel Sambuc ee_wen(dep); 147433d6423SLionel Sambuc 148433d6423SLionel Sambuc set_ee_word(dep, 0x78/2, 0x10ec); 149433d6423SLionel Sambuc set_ee_word(dep, 0x7A/2, 0x8029); 150433d6423SLionel Sambuc set_ee_word(dep, 0x7C/2, 0x10ec); 151433d6423SLionel Sambuc set_ee_word(dep, 0x7E/2, 0x8029); 152433d6423SLionel Sambuc 153433d6423SLionel Sambuc ee_wds(dep); 154433d6423SLionel Sambuc 155433d6423SLionel Sambuc assert(get_ee_word(dep, 0x78/2) == 0x10ec); 156433d6423SLionel Sambuc assert(get_ee_word(dep, 0x7A/2) == 0x8029); 157433d6423SLionel Sambuc assert(get_ee_word(dep, 0x7C/2) == 0x10ec); 158433d6423SLionel Sambuc assert(get_ee_word(dep, 0x7E/2) == 0x8029); 159433d6423SLionel Sambuc } 160433d6423SLionel Sambuc 161433d6423SLionel Sambuc if (getenv("RTL8029XXX")) 162433d6423SLionel Sambuc { 163433d6423SLionel Sambuc ee_wen(dep); 164433d6423SLionel Sambuc 165433d6423SLionel Sambuc set_ee_word(dep, 0x76/2, 0x8029); 166433d6423SLionel Sambuc 167433d6423SLionel Sambuc ee_wds(dep); 168433d6423SLionel Sambuc 169433d6423SLionel Sambuc assert(get_ee_word(dep, 0x76/2) == 0x8029); 170433d6423SLionel Sambuc } 171433d6423SLionel Sambuc #endif 172433d6423SLionel Sambuc } 173433d6423SLionel Sambuc 174433d6423SLionel Sambuc #if 0 175433d6423SLionel Sambuc static u16_t get_ee_word(dep, a) 176433d6423SLionel Sambuc dpeth_t *dep; 177433d6423SLionel Sambuc int a; 178433d6423SLionel Sambuc { 179433d6423SLionel Sambuc int b, i, cmd; 180433d6423SLionel Sambuc u16_t w; 181433d6423SLionel Sambuc 182433d6423SLionel Sambuc outb_reg0(dep, DP_CR, CR_PS_P3); /* Bank 3 */ 183433d6423SLionel Sambuc 184433d6423SLionel Sambuc /* Switch to 9346 mode and enable CS */ 185433d6423SLionel Sambuc outb_reg3(dep, 1, 0x80 | 0x8); 186433d6423SLionel Sambuc 187433d6423SLionel Sambuc cmd= 0x180 | (a & 0x3f); /* 1 1 0 a5 a4 a3 a2 a1 a0 */ 188433d6423SLionel Sambuc for (i= 8; i >= 0; i--) 189433d6423SLionel Sambuc { 190433d6423SLionel Sambuc b= (cmd & (1 << i)); 191433d6423SLionel Sambuc b= (b ? 2 : 0); 192433d6423SLionel Sambuc 193433d6423SLionel Sambuc /* Cmd goes out on the rising edge of the clock */ 194433d6423SLionel Sambuc outb_reg3(dep, 1, 0x80 | 0x8 | b); 195433d6423SLionel Sambuc outb_reg3(dep, 1, 0x80 | 0x8 | 0x4 | b); 196433d6423SLionel Sambuc } 197433d6423SLionel Sambuc outb_reg3(dep, 1, 0x80 | 0x8); /* End of cmd */ 198433d6423SLionel Sambuc 199433d6423SLionel Sambuc w= 0; 200433d6423SLionel Sambuc for (i= 0; i<16; i++) 201433d6423SLionel Sambuc { 202433d6423SLionel Sambuc w <<= 1; 203433d6423SLionel Sambuc 204433d6423SLionel Sambuc /* Data is shifted out on the rising edge. Read at the 205433d6423SLionel Sambuc * falling edge. 206433d6423SLionel Sambuc */ 207433d6423SLionel Sambuc outb_reg3(dep, 1, 0x80 | 0x8 | 0x4); 208433d6423SLionel Sambuc outb_reg3(dep, 1, 0x80 | 0x8 | b); 209433d6423SLionel Sambuc b= inb_reg3(dep, 1); 210433d6423SLionel Sambuc w |= (b & 1); 211433d6423SLionel Sambuc } 212433d6423SLionel Sambuc 213433d6423SLionel Sambuc outb_reg3(dep, 1, 0x80); /* drop CS */ 214433d6423SLionel Sambuc outb_reg3(dep, 1, 0x00); /* back to normal */ 215433d6423SLionel Sambuc outb_reg0(dep, DP_CR, CR_PS_P0); /* back to bank 0 */ 216433d6423SLionel Sambuc 217433d6423SLionel Sambuc return w; 218433d6423SLionel Sambuc } 219433d6423SLionel Sambuc 220433d6423SLionel Sambuc static void ee_wen(dep) 221433d6423SLionel Sambuc dpeth_t *dep; 222433d6423SLionel Sambuc { 223433d6423SLionel Sambuc int b, i, cmd; 224433d6423SLionel Sambuc 225433d6423SLionel Sambuc outb_reg0(dep, DP_CR, CR_PS_P3); /* Bank 3 */ 226433d6423SLionel Sambuc 227433d6423SLionel Sambuc /* Switch to 9346 mode and enable CS */ 228433d6423SLionel Sambuc outb_reg3(dep, 1, 0x80 | 0x8); 229433d6423SLionel Sambuc 230433d6423SLionel Sambuc cmd= 0x130; /* 1 0 0 1 1 x x x x */ 231433d6423SLionel Sambuc for (i= 8; i >= 0; i--) 232433d6423SLionel Sambuc { 233433d6423SLionel Sambuc b= (cmd & (1 << i)); 234433d6423SLionel Sambuc b= (b ? 2 : 0); 235433d6423SLionel Sambuc 236433d6423SLionel Sambuc /* Cmd goes out on the rising edge of the clock */ 237433d6423SLionel Sambuc outb_reg3(dep, 1, 0x80 | 0x8 | b); 238433d6423SLionel Sambuc outb_reg3(dep, 1, 0x80 | 0x8 | 0x4 | b); 239433d6423SLionel Sambuc } 240433d6423SLionel Sambuc outb_reg3(dep, 1, 0x80 | 0x8); /* End of cmd */ 241433d6423SLionel Sambuc outb_reg3(dep, 1, 0x80); /* Drop CS */ 242433d6423SLionel Sambuc micro_delay(1); /* Is this required? */ 243433d6423SLionel Sambuc } 244433d6423SLionel Sambuc 245433d6423SLionel Sambuc static void set_ee_word(dep, a, w) 246433d6423SLionel Sambuc dpeth_t *dep; 247433d6423SLionel Sambuc int a; 248433d6423SLionel Sambuc u16_t w; 249433d6423SLionel Sambuc { 250433d6423SLionel Sambuc int b, i, cmd; 251433d6423SLionel Sambuc 252433d6423SLionel Sambuc outb_reg3(dep, 1, 0x80 | 0x8); /* Set CS */ 253433d6423SLionel Sambuc 254433d6423SLionel Sambuc cmd= 0x140 | (a & 0x3f); /* 1 0 1 a5 a4 a3 a2 a1 a0 */ 255433d6423SLionel Sambuc for (i= 8; i >= 0; i--) 256433d6423SLionel Sambuc { 257433d6423SLionel Sambuc b= (cmd & (1 << i)); 258433d6423SLionel Sambuc b= (b ? 2 : 0); 259433d6423SLionel Sambuc 260433d6423SLionel Sambuc /* Cmd goes out on the rising edge of the clock */ 261433d6423SLionel Sambuc outb_reg3(dep, 1, 0x80 | 0x8 | b); 262433d6423SLionel Sambuc outb_reg3(dep, 1, 0x80 | 0x8 | 0x4 | b); 263433d6423SLionel Sambuc } 264433d6423SLionel Sambuc for (i= 15; i >= 0; i--) 265433d6423SLionel Sambuc { 266433d6423SLionel Sambuc b= (w & (1 << i)); 267433d6423SLionel Sambuc b= (b ? 2 : 0); 268433d6423SLionel Sambuc 269433d6423SLionel Sambuc /* Cmd goes out on the rising edge of the clock */ 270433d6423SLionel Sambuc outb_reg3(dep, 1, 0x80 | 0x8 | b); 271433d6423SLionel Sambuc outb_reg3(dep, 1, 0x80 | 0x8 | 0x4 | b); 272433d6423SLionel Sambuc } 273433d6423SLionel Sambuc outb_reg3(dep, 1, 0x80 | 0x8); /* End of data */ 274433d6423SLionel Sambuc outb_reg3(dep, 1, 0x80); /* Drop CS */ 275433d6423SLionel Sambuc micro_delay(1); /* Is this required? */ 276433d6423SLionel Sambuc outb_reg3(dep, 1, 0x80 | 0x8); /* Set CS */ 277433d6423SLionel Sambuc for (i= 0; i<10000; i++) 278433d6423SLionel Sambuc { 279433d6423SLionel Sambuc if (inb_reg3(dep, 1) & 1) 280433d6423SLionel Sambuc break; 281433d6423SLionel Sambuc micro_delay(1); 282433d6423SLionel Sambuc } 283433d6423SLionel Sambuc if (!(inb_reg3(dep, 1) & 1)) 284433d6423SLionel Sambuc panic("set_ee_word: device remains busy"); 285433d6423SLionel Sambuc } 286433d6423SLionel Sambuc 287433d6423SLionel Sambuc static void ee_wds(dep) 288433d6423SLionel Sambuc dpeth_t *dep; 289433d6423SLionel Sambuc { 290433d6423SLionel Sambuc int b, i, cmd; 291433d6423SLionel Sambuc 292433d6423SLionel Sambuc outb_reg0(dep, DP_CR, CR_PS_P3); /* Bank 3 */ 293433d6423SLionel Sambuc 294433d6423SLionel Sambuc /* Switch to 9346 mode and enable CS */ 295433d6423SLionel Sambuc outb_reg3(dep, 1, 0x80 | 0x8); 296433d6423SLionel Sambuc 297433d6423SLionel Sambuc cmd= 0x100; /* 1 0 0 0 0 x x x x */ 298433d6423SLionel Sambuc for (i= 8; i >= 0; i--) 299433d6423SLionel Sambuc { 300433d6423SLionel Sambuc b= (cmd & (1 << i)); 301433d6423SLionel Sambuc b= (b ? 2 : 0); 302433d6423SLionel Sambuc 303433d6423SLionel Sambuc /* Cmd goes out on the rising edge of the clock */ 304433d6423SLionel Sambuc outb_reg3(dep, 1, 0x80 | 0x8 | b); 305433d6423SLionel Sambuc outb_reg3(dep, 1, 0x80 | 0x8 | 0x4 | b); 306433d6423SLionel Sambuc } 307433d6423SLionel Sambuc outb_reg3(dep, 1, 0x80 | 0x8); /* End of cmd */ 308433d6423SLionel Sambuc outb_reg3(dep, 1, 0x80); /* Drop CS */ 309433d6423SLionel Sambuc outb_reg3(dep, 1, 0x00); /* back to normal */ 310433d6423SLionel Sambuc outb_reg0(dep, DP_CR, CR_PS_P0); /* back to bank 0 */ 311433d6423SLionel Sambuc } 312433d6423SLionel Sambuc #endif 313433d6423SLionel Sambuc 314433d6423SLionel Sambuc /* 315433d6423SLionel Sambuc * $PchId: rtl8029.c,v 1.7 2004/08/03 12:16:58 philip Exp $ 316433d6423SLionel Sambuc */ 317