1*4882a593Smuzhiyun!!! WARNING !!! 2*4882a593Smuzhiyun 3*4882a593SmuzhiyunThis guide describes to the old way of doing things. No new Ethernet drivers 4*4882a593Smuzhiyunshould be implemented this way. All new drivers should be written against the 5*4882a593SmuzhiyunU-Boot core driver model. See doc/driver-model/README.txt 6*4882a593Smuzhiyun 7*4882a593Smuzhiyun----------------------- 8*4882a593Smuzhiyun Ethernet Driver Guide 9*4882a593Smuzhiyun----------------------- 10*4882a593Smuzhiyun 11*4882a593SmuzhiyunThe networking stack in Das U-Boot is designed for multiple network devices 12*4882a593Smuzhiyunto be easily added and controlled at runtime. This guide is meant for people 13*4882a593Smuzhiyunwho wish to review the net driver stack with an eye towards implementing your 14*4882a593Smuzhiyunown ethernet device driver. Here we will describe a new pseudo 'APE' driver. 15*4882a593Smuzhiyun 16*4882a593Smuzhiyun------------------ 17*4882a593Smuzhiyun Driver Functions 18*4882a593Smuzhiyun------------------ 19*4882a593Smuzhiyun 20*4882a593SmuzhiyunAll functions you will be implementing in this document have the return value 21*4882a593Smuzhiyunmeaning of 0 for success and non-zero for failure. 22*4882a593Smuzhiyun 23*4882a593Smuzhiyun ---------- 24*4882a593Smuzhiyun Register 25*4882a593Smuzhiyun ---------- 26*4882a593Smuzhiyun 27*4882a593SmuzhiyunWhen U-Boot initializes, it will call the common function eth_initialize(). 28*4882a593SmuzhiyunThis will in turn call the board-specific board_eth_init() (or if that fails, 29*4882a593Smuzhiyunthe cpu-specific cpu_eth_init()). These board-specific functions can do random 30*4882a593Smuzhiyunsystem handling, but ultimately they will call the driver-specific register 31*4882a593Smuzhiyunfunction which in turn takes care of initializing that particular instance. 32*4882a593Smuzhiyun 33*4882a593SmuzhiyunKeep in mind that you should code the driver to avoid storing state in global 34*4882a593Smuzhiyundata as someone might want to hook up two of the same devices to one board. 35*4882a593SmuzhiyunAny such information that is specific to an interface should be stored in a 36*4882a593Smuzhiyunprivate, driver-defined data structure and pointed to by eth->priv (see below). 37*4882a593Smuzhiyun 38*4882a593SmuzhiyunSo the call graph at this stage would look something like: 39*4882a593Smuzhiyunboard_init() 40*4882a593Smuzhiyun eth_initialize() 41*4882a593Smuzhiyun board_eth_init() / cpu_eth_init() 42*4882a593Smuzhiyun driver_register() 43*4882a593Smuzhiyun initialize eth_device 44*4882a593Smuzhiyun eth_register() 45*4882a593Smuzhiyun 46*4882a593SmuzhiyunAt this point in time, the only thing you need to worry about is the driver's 47*4882a593Smuzhiyunregister function. The pseudo code would look something like: 48*4882a593Smuzhiyunint ape_register(bd_t *bis, int iobase) 49*4882a593Smuzhiyun{ 50*4882a593Smuzhiyun struct ape_priv *priv; 51*4882a593Smuzhiyun struct eth_device *dev; 52*4882a593Smuzhiyun struct mii_dev *bus; 53*4882a593Smuzhiyun 54*4882a593Smuzhiyun priv = malloc(sizeof(*priv)); 55*4882a593Smuzhiyun if (priv == NULL) 56*4882a593Smuzhiyun return -ENOMEM; 57*4882a593Smuzhiyun 58*4882a593Smuzhiyun dev = malloc(sizeof(*dev)); 59*4882a593Smuzhiyun if (dev == NULL) { 60*4882a593Smuzhiyun free(priv); 61*4882a593Smuzhiyun return -ENOMEM; 62*4882a593Smuzhiyun } 63*4882a593Smuzhiyun 64*4882a593Smuzhiyun /* setup whatever private state you need */ 65*4882a593Smuzhiyun 66*4882a593Smuzhiyun memset(dev, 0, sizeof(*dev)); 67*4882a593Smuzhiyun sprintf(dev->name, "APE"); 68*4882a593Smuzhiyun 69*4882a593Smuzhiyun /* 70*4882a593Smuzhiyun * if your device has dedicated hardware storage for the 71*4882a593Smuzhiyun * MAC, read it and initialize dev->enetaddr with it 72*4882a593Smuzhiyun */ 73*4882a593Smuzhiyun ape_mac_read(dev->enetaddr); 74*4882a593Smuzhiyun 75*4882a593Smuzhiyun dev->iobase = iobase; 76*4882a593Smuzhiyun dev->priv = priv; 77*4882a593Smuzhiyun dev->init = ape_init; 78*4882a593Smuzhiyun dev->halt = ape_halt; 79*4882a593Smuzhiyun dev->send = ape_send; 80*4882a593Smuzhiyun dev->recv = ape_recv; 81*4882a593Smuzhiyun dev->write_hwaddr = ape_write_hwaddr; 82*4882a593Smuzhiyun 83*4882a593Smuzhiyun eth_register(dev); 84*4882a593Smuzhiyun 85*4882a593Smuzhiyun#ifdef CONFIG_PHYLIB 86*4882a593Smuzhiyun bus = mdio_alloc(); 87*4882a593Smuzhiyun if (!bus) { 88*4882a593Smuzhiyun free(priv); 89*4882a593Smuzhiyun free(dev); 90*4882a593Smuzhiyun return -ENOMEM; 91*4882a593Smuzhiyun } 92*4882a593Smuzhiyun 93*4882a593Smuzhiyun bus->read = ape_mii_read; 94*4882a593Smuzhiyun bus->write = ape_mii_write; 95*4882a593Smuzhiyun mdio_register(bus); 96*4882a593Smuzhiyun#endif 97*4882a593Smuzhiyun 98*4882a593Smuzhiyun return 1; 99*4882a593Smuzhiyun} 100*4882a593Smuzhiyun 101*4882a593SmuzhiyunThe exact arguments needed to initialize your device are up to you. If you 102*4882a593Smuzhiyunneed to pass more/less arguments, that's fine. You should also add the 103*4882a593Smuzhiyunprototype for your new register function to include/netdev.h. 104*4882a593Smuzhiyun 105*4882a593SmuzhiyunThe return value for this function should be as follows: 106*4882a593Smuzhiyun< 0 - failure (hardware failure, not probe failure) 107*4882a593Smuzhiyun>=0 - number of interfaces detected 108*4882a593Smuzhiyun 109*4882a593SmuzhiyunYou might notice that many drivers seem to use xxx_initialize() rather than 110*4882a593Smuzhiyunxxx_register(). This is the old naming convention and should be avoided as it 111*4882a593Smuzhiyuncauses confusion with the driver-specific init function. 112*4882a593Smuzhiyun 113*4882a593SmuzhiyunOther than locating the MAC address in dedicated hardware storage, you should 114*4882a593Smuzhiyunnot touch the hardware in anyway. That step is handled in the driver-specific 115*4882a593Smuzhiyuninit function. Remember that we are only registering the device here, we are 116*4882a593Smuzhiyunnot checking its state or doing random probing. 117*4882a593Smuzhiyun 118*4882a593Smuzhiyun ----------- 119*4882a593Smuzhiyun Callbacks 120*4882a593Smuzhiyun ----------- 121*4882a593Smuzhiyun 122*4882a593SmuzhiyunNow that we've registered with the ethernet layer, we can start getting some 123*4882a593Smuzhiyunreal work done. You will need five functions: 124*4882a593Smuzhiyun int ape_init(struct eth_device *dev, bd_t *bis); 125*4882a593Smuzhiyun int ape_send(struct eth_device *dev, volatile void *packet, int length); 126*4882a593Smuzhiyun int ape_recv(struct eth_device *dev); 127*4882a593Smuzhiyun int ape_halt(struct eth_device *dev); 128*4882a593Smuzhiyun int ape_write_hwaddr(struct eth_device *dev); 129*4882a593Smuzhiyun 130*4882a593SmuzhiyunThe init function checks the hardware (probing/identifying) and gets it ready 131*4882a593Smuzhiyunfor send/recv operations. You often do things here such as resetting the MAC 132*4882a593Smuzhiyunand/or PHY, and waiting for the link to autonegotiate. You should also take 133*4882a593Smuzhiyunthe opportunity to program the device's MAC address with the dev->enetaddr 134*4882a593Smuzhiyunmember. This allows the rest of U-Boot to dynamically change the MAC address 135*4882a593Smuzhiyunand have the new settings be respected. 136*4882a593Smuzhiyun 137*4882a593SmuzhiyunThe send function does what you think -- transmit the specified packet whose 138*4882a593Smuzhiyunsize is specified by length (in bytes). You should not return until the 139*4882a593Smuzhiyuntransmission is complete, and you should leave the state such that the send 140*4882a593Smuzhiyunfunction can be called multiple times in a row. 141*4882a593Smuzhiyun 142*4882a593SmuzhiyunThe recv function should process packets as long as the hardware has them 143*4882a593Smuzhiyunreadily available before returning. i.e. you should drain the hardware fifo. 144*4882a593SmuzhiyunFor each packet you receive, you should call the net_process_received_packet() function on it 145*4882a593Smuzhiyunalong with the packet length. The common code sets up packet buffers for you 146*4882a593Smuzhiyunalready in the .bss (net_rx_packets), so there should be no need to allocate your 147*4882a593Smuzhiyunown. This doesn't mean you must use the net_rx_packets array however; you're 148*4882a593Smuzhiyunfree to call the net_process_received_packet() function with any buffer you wish. So the pseudo 149*4882a593Smuzhiyuncode here would look something like: 150*4882a593Smuzhiyunint ape_recv(struct eth_device *dev) 151*4882a593Smuzhiyun{ 152*4882a593Smuzhiyun int length, i = 0; 153*4882a593Smuzhiyun ... 154*4882a593Smuzhiyun while (packets_are_available()) { 155*4882a593Smuzhiyun ... 156*4882a593Smuzhiyun length = ape_get_packet(&net_rx_packets[i]); 157*4882a593Smuzhiyun ... 158*4882a593Smuzhiyun net_process_received_packet(&net_rx_packets[i], length); 159*4882a593Smuzhiyun ... 160*4882a593Smuzhiyun if (++i >= PKTBUFSRX) 161*4882a593Smuzhiyun i = 0; 162*4882a593Smuzhiyun ... 163*4882a593Smuzhiyun } 164*4882a593Smuzhiyun ... 165*4882a593Smuzhiyun return 0; 166*4882a593Smuzhiyun} 167*4882a593Smuzhiyun 168*4882a593SmuzhiyunThe halt function should turn off / disable the hardware and place it back in 169*4882a593Smuzhiyunits reset state. It can be called at any time (before any call to the related 170*4882a593Smuzhiyuninit function), so make sure it can handle this sort of thing. 171*4882a593Smuzhiyun 172*4882a593SmuzhiyunThe write_hwaddr function should program the MAC address stored in dev->enetaddr 173*4882a593Smuzhiyuninto the Ethernet controller. 174*4882a593Smuzhiyun 175*4882a593SmuzhiyunSo the call graph at this stage would look something like: 176*4882a593Smuzhiyunsome net operation (ping / tftp / whatever...) 177*4882a593Smuzhiyun eth_init() 178*4882a593Smuzhiyun dev->init() 179*4882a593Smuzhiyun eth_send() 180*4882a593Smuzhiyun dev->send() 181*4882a593Smuzhiyun eth_rx() 182*4882a593Smuzhiyun dev->recv() 183*4882a593Smuzhiyun eth_halt() 184*4882a593Smuzhiyun dev->halt() 185*4882a593Smuzhiyun 186*4882a593Smuzhiyun-------------------------------- 187*4882a593Smuzhiyun CONFIG_PHYLIB / CONFIG_CMD_MII 188*4882a593Smuzhiyun-------------------------------- 189*4882a593Smuzhiyun 190*4882a593SmuzhiyunIf your device supports banging arbitrary values on the MII bus (pretty much 191*4882a593Smuzhiyunevery device does), you should add support for the mii command. Doing so is 192*4882a593Smuzhiyunfairly trivial and makes debugging mii issues a lot easier at runtime. 193*4882a593Smuzhiyun 194*4882a593SmuzhiyunAfter you have called eth_register() in your driver's register function, add 195*4882a593Smuzhiyuna call to mdio_alloc() and mdio_register() like so: 196*4882a593Smuzhiyun bus = mdio_alloc(); 197*4882a593Smuzhiyun if (!bus) { 198*4882a593Smuzhiyun free(priv); 199*4882a593Smuzhiyun free(dev); 200*4882a593Smuzhiyun return -ENOMEM; 201*4882a593Smuzhiyun } 202*4882a593Smuzhiyun 203*4882a593Smuzhiyun bus->read = ape_mii_read; 204*4882a593Smuzhiyun bus->write = ape_mii_write; 205*4882a593Smuzhiyun mdio_register(bus); 206*4882a593Smuzhiyun 207*4882a593SmuzhiyunAnd then define the mii_read and mii_write functions if you haven't already. 208*4882a593SmuzhiyunTheir syntax is straightforward: 209*4882a593Smuzhiyun int mii_read(struct mii_dev *bus, int addr, int devad, int reg); 210*4882a593Smuzhiyun int mii_write(struct mii_dev *bus, int addr, int devad, int reg, 211*4882a593Smuzhiyun u16 val); 212*4882a593Smuzhiyun 213*4882a593SmuzhiyunThe read function should read the register 'reg' from the phy at address 'addr' 214*4882a593Smuzhiyunand return the result to its caller. The implementation for the write function 215*4882a593Smuzhiyunshould logically follow. 216