diff options
Diffstat (limited to 'qemu/roms/u-boot/doc/README.drivers.eth')
-rw-r--r-- | qemu/roms/u-boot/doc/README.drivers.eth | 190 |
1 files changed, 0 insertions, 190 deletions
diff --git a/qemu/roms/u-boot/doc/README.drivers.eth b/qemu/roms/u-boot/doc/README.drivers.eth deleted file mode 100644 index eb83038b5..000000000 --- a/qemu/roms/u-boot/doc/README.drivers.eth +++ /dev/null @@ -1,190 +0,0 @@ ------------------------ - Ethernet Driver Guide ------------------------ - -The networking stack in Das U-Boot is designed for multiple network devices -to be easily added and controlled at runtime. This guide is meant for people -who wish to review the net driver stack with an eye towards implementing your -own ethernet device driver. Here we will describe a new pseudo 'APE' driver. - ------------------- - Driver Functions ------------------- - -All functions you will be implementing in this document have the return value -meaning of 0 for success and non-zero for failure. - - ---------- - Register - ---------- - -When U-Boot initializes, it will call the common function eth_initialize(). -This will in turn call the board-specific board_eth_init() (or if that fails, -the cpu-specific cpu_eth_init()). These board-specific functions can do random -system handling, but ultimately they will call the driver-specific register -function which in turn takes care of initializing that particular instance. - -Keep in mind that you should code the driver to avoid storing state in global -data as someone might want to hook up two of the same devices to one board. -Any such information that is specific to an interface should be stored in a -private, driver-defined data structure and pointed to by eth->priv (see below). - -So the call graph at this stage would look something like: -board_init() - eth_initialize() - board_eth_init() / cpu_eth_init() - driver_register() - initialize eth_device - eth_register() - -At this point in time, the only thing you need to worry about is the driver's -register function. The pseudo code would look something like: -int ape_register(bd_t *bis, int iobase) -{ - struct ape_priv *priv; - struct eth_device *dev; - - priv = malloc(sizeof(*priv)); - if (priv == NULL) - return 1; - - dev = malloc(sizeof(*dev)); - if (dev == NULL) { - free(priv); - return 1; - } - - /* setup whatever private state you need */ - - memset(dev, 0, sizeof(*dev)); - sprintf(dev->name, "APE"); - - /* if your device has dedicated hardware storage for the - * MAC, read it and initialize dev->enetaddr with it - */ - ape_mac_read(dev->enetaddr); - - dev->iobase = iobase; - dev->priv = priv; - dev->init = ape_init; - dev->halt = ape_halt; - dev->send = ape_send; - dev->recv = ape_recv; - dev->write_hwaddr = ape_write_hwaddr; - - eth_register(dev); - -#ifdef CONFIG_CMD_MII) - miiphy_register(dev->name, ape_mii_read, ape_mii_write); -#endif - - return 1; -} - -The exact arguments needed to initialize your device are up to you. If you -need to pass more/less arguments, that's fine. You should also add the -prototype for your new register function to include/netdev.h. - -The return value for this function should be as follows: -< 0 - failure (hardware failure, not probe failure) ->=0 - number of interfaces detected - -You might notice that many drivers seem to use xxx_initialize() rather than -xxx_register(). This is the old naming convention and should be avoided as it -causes confusion with the driver-specific init function. - -Other than locating the MAC address in dedicated hardware storage, you should -not touch the hardware in anyway. That step is handled in the driver-specific -init function. Remember that we are only registering the device here, we are -not checking its state or doing random probing. - - ----------- - Callbacks - ----------- - -Now that we've registered with the ethernet layer, we can start getting some -real work done. You will need five functions: - int ape_init(struct eth_device *dev, bd_t *bis); - int ape_send(struct eth_device *dev, volatile void *packet, int length); - int ape_recv(struct eth_device *dev); - int ape_halt(struct eth_device *dev); - int ape_write_hwaddr(struct eth_device *dev); - -The init function checks the hardware (probing/identifying) and gets it ready -for send/recv operations. You often do things here such as resetting the MAC -and/or PHY, and waiting for the link to autonegotiate. You should also take -the opportunity to program the device's MAC address with the dev->enetaddr -member. This allows the rest of U-Boot to dynamically change the MAC address -and have the new settings be respected. - -The send function does what you think -- transmit the specified packet whose -size is specified by length (in bytes). You should not return until the -transmission is complete, and you should leave the state such that the send -function can be called multiple times in a row. - -The recv function should process packets as long as the hardware has them -readily available before returning. i.e. you should drain the hardware fifo. -For each packet you receive, you should call the NetReceive() function on it -along with the packet length. The common code sets up packet buffers for you -already in the .bss (NetRxPackets), so there should be no need to allocate your -own. This doesn't mean you must use the NetRxPackets array however; you're -free to call the NetReceive() function with any buffer you wish. So the pseudo -code here would look something like: -int ape_recv(struct eth_device *dev) -{ - int length, i = 0; - ... - while (packets_are_available()) { - ... - length = ape_get_packet(&NetRxPackets[i]); - ... - NetReceive(&NetRxPackets[i], length); - ... - if (++i >= PKTBUFSRX) - i = 0; - ... - } - ... - return 0; -} - -The halt function should turn off / disable the hardware and place it back in -its reset state. It can be called at any time (before any call to the related -init function), so make sure it can handle this sort of thing. - -The write_hwaddr function should program the MAC address stored in dev->enetaddr -into the Ethernet controller. - -So the call graph at this stage would look something like: -some net operation (ping / tftp / whatever...) - eth_init() - dev->init() - eth_send() - dev->send() - eth_rx() - dev->recv() - eth_halt() - dev->halt() - ------------------------------ - CONFIG_MII / CONFIG_CMD_MII ------------------------------ - -If your device supports banging arbitrary values on the MII bus (pretty much -every device does), you should add support for the mii command. Doing so is -fairly trivial and makes debugging mii issues a lot easier at runtime. - -After you have called eth_register() in your driver's register function, add -a call to miiphy_register() like so: -#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) - miiphy_register(dev->name, mii_read, mii_write); -#endif - -And then define the mii_read and mii_write functions if you haven't already. -Their syntax is straightforward: - int mii_read(char *devname, uchar addr, uchar reg, ushort *val); - int mii_write(char *devname, uchar addr, uchar reg, ushort val); - -The read function should read the register 'reg' from the phy at address 'addr' -and store the result in the pointer 'val'. The implementation for the write -function should logically follow. |