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