The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/drivers/dp8390/rtl8029.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 4c2523c74c6cd2c1a634cf5b6b557f10


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.