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