Line No. | Rev | Author | Line |
---|---|---|---|
1 | 6 | kaklik | /*! \file rtl8019.c \brief Realtek RTL8019AS Ethernet Interface Driver. */ |
2 | //***************************************************************************** |
||
3 | // |
||
4 | // File Name : 'rtl8019.c' |
||
5 | // Title : Realtek RTL8019AS Ethernet Interface Driver |
||
6 | // Author : Pascal Stang |
||
7 | // Created : 7/6/2004 |
||
8 | // Revised : 10/1/2005 |
||
9 | // Version : 0.1 |
||
10 | // Target MCU : Atmel AVR series |
||
11 | // Editor Tabs : 4 |
||
12 | // |
||
13 | // Based in part on code by Louis Beaudoin (www.embedded-creations.com). |
||
14 | // Thanks to Adam Dunkels and Louis Beaudoin for providing the initial |
||
15 | // structure in which to write this driver. |
||
16 | //***************************************************************************** |
||
17 | |||
18 | #include "global.h" |
||
19 | #include "timer.h" |
||
20 | #include "rprintf.h" |
||
21 | |||
22 | #include "rtl8019.h" |
||
23 | |||
24 | // include configuration |
||
25 | #include "rtl8019conf.h" |
||
26 | |||
27 | // pointers to locations in the RTL8019 receive buffer |
||
28 | static unsigned char NextPage; // page pointer to next Rx packet |
||
29 | static unsigned int CurrentRetreiveAddress; // DMA address for read Rx packet location |
||
30 | |||
31 | |||
32 | void nicInit(void) |
||
33 | { |
||
34 | rtl8019Init(); |
||
35 | } |
||
36 | |||
37 | void nicSend(unsigned int len, unsigned char* packet) |
||
38 | { |
||
39 | rtl8019BeginPacketSend(len); |
||
40 | rtl8019SendPacketData(packet, len); |
||
41 | rtl8019EndPacketSend(); |
||
42 | } |
||
43 | |||
44 | unsigned int nicPoll(unsigned int maxlen, unsigned char* packet) |
||
45 | { |
||
46 | unsigned int packetLength; |
||
47 | |||
48 | packetLength = rtl8019BeginPacketRetreive(); |
||
49 | |||
50 | // if there's no packet or an error - exit without ending the operation |
||
51 | if( !packetLength ) |
||
52 | return 0; |
||
53 | |||
54 | // drop anything too big for the buffer |
||
55 | if( packetLength > maxlen ) |
||
56 | { |
||
57 | rtl8019EndPacketRetreive(); |
||
58 | return 0; |
||
59 | } |
||
60 | |||
61 | // copy the packet data into the packet buffer |
||
62 | rtl8019RetreivePacketData( packet, packetLength ); |
||
63 | rtl8019EndPacketRetreive(); |
||
64 | |||
65 | return packetLength; |
||
66 | } |
||
67 | |||
68 | void nicGetMacAddress(u08* macaddr) |
||
69 | { |
||
70 | u08 tempCR; |
||
71 | // switch register pages |
||
72 | tempCR = rtl8019Read(CR); |
||
73 | rtl8019Write(CR,tempCR|PS0); |
||
74 | // read MAC address registers |
||
75 | *macaddr++ = rtl8019Read(PAR0); |
||
76 | *macaddr++ = rtl8019Read(PAR1); |
||
77 | *macaddr++ = rtl8019Read(PAR2); |
||
78 | *macaddr++ = rtl8019Read(PAR3); |
||
79 | *macaddr++ = rtl8019Read(PAR4); |
||
80 | *macaddr++ = rtl8019Read(PAR5); |
||
81 | // switch register pages back |
||
82 | rtl8019Write(CR,tempCR); |
||
83 | } |
||
84 | |||
85 | void nicSetMacAddress(u08* macaddr) |
||
86 | { |
||
87 | u08 tempCR; |
||
88 | // switch register pages |
||
89 | tempCR = rtl8019Read(CR); |
||
90 | rtl8019Write(CR,tempCR|PS0); |
||
91 | // write MAC address registers |
||
92 | rtl8019Write(PAR0, *macaddr++); |
||
93 | rtl8019Write(PAR1, *macaddr++); |
||
94 | rtl8019Write(PAR2, *macaddr++); |
||
95 | rtl8019Write(PAR3, *macaddr++); |
||
96 | rtl8019Write(PAR4, *macaddr++); |
||
97 | rtl8019Write(PAR5, *macaddr++); |
||
98 | // switch register pages back |
||
99 | rtl8019Write(CR,tempCR); |
||
100 | } |
||
101 | |||
102 | void nicRegDump(void) |
||
103 | { |
||
104 | rtl8019RegDump(); |
||
105 | } |
||
106 | |||
107 | |||
108 | void rtl8019SetupPorts(void) |
||
109 | { |
||
110 | #if NIC_CONNECTION == MEMORY_MAPPED |
||
111 | // enable external SRAM interface - no wait states |
||
112 | sbi(MCUCR, SRE); |
||
113 | // sbi(MCUCR, SRW10); |
||
114 | // sbi(XMCRA, SRW00); |
||
115 | // sbi(XMCRA, SRW01); |
||
116 | // sbi(XMCRA, SRW11); |
||
117 | #else |
||
118 | // make the address port output |
||
119 | RTL8019_ADDRESS_DDR |= RTL8019_ADDRESS_MASK; |
||
120 | // make the data port input with pull-ups |
||
121 | RTL8019_DATA_PORT = 0xFF; |
||
122 | |||
123 | // initialize the control port read and write pins to de-asserted |
||
124 | RTL8019_CONTROL_DDR |= (1<<RTL8019_CONTROL_READPIN); |
||
125 | RTL8019_CONTROL_DDR |= (1<<RTL8019_CONTROL_WRITEPIN); |
||
126 | // set the read and write pins to output |
||
127 | RTL8019_CONTROL_PORT |= (1<<RTL8019_CONTROL_READPIN); |
||
128 | RTL8019_CONTROL_PORT |= (1<<RTL8019_CONTROL_WRITEPIN); |
||
129 | #endif |
||
130 | // set reset pin to output |
||
131 | sbi(RTL8019_RESET_DDR, RTL8019_RESET_PIN); |
||
132 | } |
||
133 | |||
134 | |||
135 | #if NIC_CONNECTION == MEMORY_MAPPED |
||
136 | inline void rtl8019Write(u08 address, u08 data) |
||
137 | { |
||
138 | *(volatile u08*)(RTL8019_MEMORY_MAPPED_OFFSET + address) = data; |
||
139 | } |
||
140 | #else |
||
141 | void rtl8019Write(unsigned char address, unsigned char data) |
||
142 | { |
||
143 | // assert the address |
||
144 | RTL8019_ADDRESS_PORT = address | (RTL8019_ADDRESS_PORT&~RTL8019_ADDRESS_MASK); |
||
145 | // set data bus as output and place data on bus |
||
146 | RTL8019_DATA_DDR = 0xFF; |
||
147 | RTL8019_DATA_PORT = data; |
||
148 | // clock write pin |
||
149 | cbi(RTL8019_CONTROL_PORT, RTL8019_CONTROL_WRITEPIN); |
||
150 | nop(); |
||
151 | nop(); |
||
152 | sbi(RTL8019_CONTROL_PORT, RTL8019_CONTROL_WRITEPIN); |
||
153 | // set data port back to input with pullups enabled |
||
154 | RTL8019_DATA_DDR = 0x00; |
||
155 | RTL8019_DATA_PORT = 0xFF; |
||
156 | } |
||
157 | #endif |
||
158 | |||
159 | |||
160 | #if NIC_CONNECTION == MEMORY_MAPPED |
||
161 | inline u08 ax88796Read(u08 address) |
||
162 | { |
||
163 | return *(volatile u08*)(RTL8019_MEMORY_MAPPED_OFFSET + address); |
||
164 | } |
||
165 | #else |
||
166 | unsigned char rtl8019Read(unsigned char address) |
||
167 | { |
||
168 | unsigned char data; |
||
169 | |||
170 | // assert the address |
||
171 | RTL8019_ADDRESS_PORT = address | (RTL8019_ADDRESS_PORT&~RTL8019_ADDRESS_MASK); |
||
172 | // assert read |
||
173 | cbi(RTL8019_CONTROL_PORT, RTL8019_CONTROL_READPIN); |
||
174 | nop(); |
||
175 | nop(); |
||
176 | // read in the data |
||
177 | data = RTL8019_DATA_PIN; |
||
178 | // negate read |
||
179 | sbi(RTL8019_CONTROL_PORT, RTL8019_CONTROL_READPIN); |
||
180 | // return data |
||
181 | return data; |
||
182 | } |
||
183 | #endif |
||
184 | |||
185 | |||
186 | void rtl8019Init(void) |
||
187 | { |
||
188 | // setup I/O ports |
||
189 | rtl8019SetupPorts(); |
||
190 | |||
191 | // do a hard reset |
||
192 | sbi(RTL8019_RESET_PORT, RTL8019_RESET_PIN); |
||
193 | delay_ms(10); |
||
194 | cbi(RTL8019_RESET_PORT, RTL8019_RESET_PIN); |
||
195 | |||
196 | // clear interrupt state |
||
197 | rtl8019Write( ISR, rtl8019Read(ISR) ); |
||
198 | delay_ms(50); |
||
199 | |||
200 | // switch to page 3 to load config registers |
||
201 | rtl8019Write(CR, (PS0|PS1|RD2|STOP)); |
||
202 | |||
203 | // disable EEPROM write protect of config registers |
||
204 | rtl8019Write(RTL_EECR, (EEM1|EEM0)); |
||
205 | |||
206 | // set network type to 10 Base-T link test |
||
207 | rtl8019Write(CONFIG2, 0x20); |
||
208 | |||
209 | // disable powerdown and sleep |
||
210 | rtl8019Write(CONFIG3, 0); |
||
211 | delay_ms(255); |
||
212 | |||
213 | // reenable EEPROM write protect |
||
214 | rtl8019Write(RTL_EECR, 0); |
||
215 | |||
216 | // go back to page 0, stop NIC, abort DMA |
||
217 | rtl8019Write(CR, (RD2|STOP)); |
||
218 | delay_ms(2); // wait for traffic to complete |
||
219 | rtl8019Write(DCR, DCR_INIT); |
||
220 | rtl8019Write(RBCR0,0x00); |
||
221 | rtl8019Write(RBCR1,0x00); |
||
222 | rtl8019Write(RCR, AB); |
||
223 | rtl8019Write(TPSR, TXSTART_INIT); |
||
224 | rtl8019Write(TCR, LB0); |
||
225 | rtl8019Write(PSTART, RXSTART_INIT); |
||
226 | rtl8019Write(BNRY, RXSTART_INIT); |
||
227 | rtl8019Write(PSTOP, RXSTOP_INIT); |
||
228 | rtl8019Write(CR, (PS0|RD2|STOP)); // switch to page 1 |
||
229 | delay_ms(2); |
||
230 | rtl8019Write(CPR, RXSTART_INIT); |
||
231 | |||
232 | // set MAC address |
||
233 | rtl8019Write(PAR0, RTL8019_MAC0); |
||
234 | rtl8019Write(PAR1, RTL8019_MAC1); |
||
235 | rtl8019Write(PAR2, RTL8019_MAC2); |
||
236 | rtl8019Write(PAR3, RTL8019_MAC3); |
||
237 | rtl8019Write(PAR4, RTL8019_MAC4); |
||
238 | rtl8019Write(PAR5, RTL8019_MAC5); |
||
239 | |||
240 | // initialize sequence per NE2000 spec |
||
241 | rtl8019Write(CR, (RD2|STOP)); |
||
242 | rtl8019Write(DCR, DCR_INIT); |
||
243 | rtl8019Write(CR, (RD2|START)); |
||
244 | rtl8019Write(ISR,0xFF); // clear all interrupts |
||
245 | rtl8019Write(IMR, IMR_INIT); |
||
246 | rtl8019Write(TCR, TCR_INIT); |
||
247 | |||
248 | rtl8019Write(CR, (RD2|START)); // start the NIC |
||
249 | } |
||
250 | |||
251 | |||
252 | void rtl8019BeginPacketSend(unsigned int packetLength) |
||
253 | { |
||
254 | unsigned int sendPacketLength; |
||
255 | sendPacketLength = (packetLength>=ETHERNET_MIN_PACKET_LENGTH)? |
||
256 | (packetLength):ETHERNET_MIN_PACKET_LENGTH; |
||
257 | |||
258 | //start the NIC |
||
259 | rtl8019Write(CR, (RD2|START)); |
||
260 | |||
261 | // still transmitting a packet - wait for it to finish |
||
262 | while( rtl8019Read(CR) & TXP ); |
||
263 | |||
264 | // load beginning page for transmit buffer |
||
265 | rtl8019Write(TPSR,TXSTART_INIT); |
||
266 | |||
267 | // set start address for remote DMA operation |
||
268 | rtl8019Write(RSAR0,0x00); |
||
269 | rtl8019Write(RSAR1,0x40); |
||
270 | |||
271 | // clear the packet stored interrupt |
||
272 | rtl8019Write(ISR,PTX); |
||
273 | |||
274 | // load data byte count for remote DMA |
||
275 | rtl8019Write(RBCR0, (unsigned char)(packetLength)); |
||
276 | rtl8019Write(RBCR1, (unsigned char)(packetLength>>8)); |
||
277 | |||
278 | rtl8019Write(TBCR0, (unsigned char)(sendPacketLength)); |
||
279 | rtl8019Write(TBCR1, (unsigned char)((sendPacketLength)>>8)); |
||
280 | |||
281 | // do remote write operation |
||
282 | rtl8019Write(CR,(RD1|START)); |
||
283 | } |
||
284 | |||
285 | |||
286 | void rtl8019SendPacketData(unsigned char *localBuffer, unsigned int length) |
||
287 | { |
||
288 | unsigned int i; |
||
289 | |||
290 | // write data to DMA port |
||
291 | for(i=0;i<length;i++) |
||
292 | rtl8019Write(RDMAPORT, localBuffer[i]); |
||
293 | } |
||
294 | |||
295 | |||
296 | void rtl8019EndPacketSend(void) |
||
297 | { |
||
298 | //send the contents of the transmit buffer onto the network |
||
299 | rtl8019Write(CR,(RD2|TXP)); |
||
300 | // clear the remote DMA interrupt |
||
301 | rtl8019Write(ISR, RDC); |
||
302 | } |
||
303 | |||
304 | |||
305 | unsigned int rtl8019BeginPacketRetreive(void) |
||
306 | { |
||
307 | unsigned char i; |
||
308 | unsigned char bnry; |
||
309 | |||
310 | unsigned char pageheader[4]; |
||
311 | unsigned int rxlen; |
||
312 | |||
313 | // check for and handle an overflow |
||
314 | rtl8019ProcessInterrupt(); |
||
315 | |||
316 | // read CPR from page 1 |
||
317 | rtl8019Write(CR,(PS0|RD2|START)); |
||
318 | i = rtl8019Read(CPR); |
||
319 | |||
320 | // return to page 0 |
||
321 | rtl8019Write(CR,(RD2|START)); |
||
322 | |||
323 | // read the boundary register - pointing to the beginning of the packet |
||
324 | bnry = rtl8019Read(BNRY) ; |
||
325 | |||
326 | // return if there is no packet in the buffer |
||
327 | if( bnry == i ) |
||
328 | return 0; |
||
329 | |||
330 | // clear the packet received interrupt flag |
||
331 | rtl8019Write(ISR, PRX); |
||
332 | |||
333 | // if boundary pointer is invalid |
||
334 | if( (bnry >= RXSTOP_INIT) || (bnry < RXSTART_INIT) ) |
||
335 | { |
||
336 | // reset the contents of the buffer and exit |
||
337 | rtl8019Write(BNRY, RXSTART_INIT); |
||
338 | rtl8019Write(CR, (PS0|RD2|START)); |
||
339 | rtl8019Write(CPR, RXSTART_INIT); |
||
340 | rtl8019Write(CR, (RD2|START)); |
||
341 | return 0; |
||
342 | } |
||
343 | |||
344 | // initiate DMA to transfer the RTL8019 packet header |
||
345 | rtl8019Write(RBCR0, 4); |
||
346 | rtl8019Write(RBCR1, 0); |
||
347 | rtl8019Write(RSAR0, 0); |
||
348 | rtl8019Write(RSAR1, bnry); |
||
349 | rtl8019Write(CR, (RD0|START)); |
||
350 | // transfer packet header |
||
351 | for(i=0;i<4;i++) |
||
352 | pageheader[i] = rtl8019Read(RDMAPORT); |
||
353 | // end the DMA operation |
||
354 | rtl8019Write(CR, (RD2|START)); |
||
355 | // wait for remote DMA complete |
||
356 | for(i = 0; i < 20; i++) |
||
357 | if(rtl8019Read(ISR) & RDC) |
||
358 | break; |
||
359 | rtl8019Write(ISR, RDC); |
||
360 | |||
361 | rxlen = (pageheader[PKTHEADER_PKTLENH]<<8) + pageheader[PKTHEADER_PKTLENL]; |
||
362 | NextPage = pageheader[PKTHEADER_NEXTPAGE]; |
||
363 | |||
364 | CurrentRetreiveAddress = (bnry<<8) + 4; |
||
365 | |||
366 | // if the NextPage pointer is invalid, the packet is not ready yet - exit |
||
367 | if( (NextPage >= RXSTOP_INIT) || (NextPage < RXSTART_INIT) ) |
||
368 | return 0; |
||
369 | |||
370 | return rxlen-4; |
||
371 | } |
||
372 | |||
373 | |||
374 | void rtl8019RetreivePacketData(unsigned char * localBuffer, unsigned int length) |
||
375 | { |
||
376 | unsigned int i; |
||
377 | |||
378 | // initiate DMA to transfer the data |
||
379 | rtl8019Write(RBCR0, (unsigned char)length); |
||
380 | rtl8019Write(RBCR1, (unsigned char)(length>>8)); |
||
381 | rtl8019Write(RSAR0, (unsigned char)CurrentRetreiveAddress); |
||
382 | rtl8019Write(RSAR1, (unsigned char)(CurrentRetreiveAddress>>8)); |
||
383 | rtl8019Write(CR, (RD0|START)); |
||
384 | // transfer packet data |
||
385 | for(i=0;i<length;i++) |
||
386 | localBuffer[i] = rtl8019Read(RDMAPORT); |
||
387 | // end the DMA operation |
||
388 | rtl8019Write(CR, (RD2|START)); |
||
389 | // wait for remote DMA complete |
||
390 | for(i=0; i<20; i++) |
||
391 | if(rtl8019Read(ISR) & RDC) |
||
392 | break; |
||
393 | rtl8019Write(ISR, RDC); |
||
394 | // keep track of current address |
||
395 | CurrentRetreiveAddress += length; |
||
396 | if( CurrentRetreiveAddress >= 0x6000 ) |
||
397 | CurrentRetreiveAddress = CurrentRetreiveAddress - (0x6000-0x4600) ; |
||
398 | } |
||
399 | |||
400 | |||
401 | void rtl8019EndPacketRetreive(void) |
||
402 | { |
||
403 | unsigned char i; |
||
404 | |||
405 | // end the DMA operation |
||
406 | rtl8019Write(CR, (RD2|START)); |
||
407 | // wait for remote DMA complete |
||
408 | for(i=0; i<20; i++) |
||
409 | if(rtl8019Read(ISR) & RDC) |
||
410 | break; |
||
411 | rtl8019Write(ISR, RDC); |
||
412 | |||
413 | // set the boundary register to point to the start of the next packet |
||
414 | rtl8019Write(BNRY, NextPage); |
||
415 | } |
||
416 | |||
417 | |||
418 | void rtl8019ProcessInterrupt(void) |
||
419 | { |
||
420 | unsigned char byte = rtl8019Read(ISR); |
||
421 | |||
422 | if( byte & OVW ) |
||
423 | rtl8019ReceiveOverflowRecover(); |
||
424 | } |
||
425 | |||
426 | void rtl8019ReceiveOverflowRecover(void) |
||
427 | { |
||
428 | unsigned char data_L, resend; |
||
429 | |||
430 | data_L = rtl8019Read(CR); |
||
431 | rtl8019Write(CR, 0x21); |
||
432 | delay_ms(2); |
||
433 | rtl8019Write(RBCR0, 0x00); |
||
434 | rtl8019Write(RBCR1, 0x00); |
||
435 | if(!(data_L & 0x04)) |
||
436 | resend = 0; |
||
437 | else if(data_L & 0x04) |
||
438 | { |
||
439 | data_L = rtl8019Read(ISR); |
||
440 | if((data_L & 0x02) || (data_L & 0x08)) |
||
441 | resend = 0; |
||
442 | else |
||
443 | resend = 1; |
||
444 | } |
||
445 | |||
446 | rtl8019Write(TCR, 0x02); |
||
447 | rtl8019Write(CR, 0x22); |
||
448 | rtl8019Write(BNRY, RXSTART_INIT); |
||
449 | rtl8019Write(CR, 0x62); |
||
450 | rtl8019Write(CPR, RXSTART_INIT); |
||
451 | rtl8019Write(CR, 0x22); |
||
452 | rtl8019Write(ISR, 0x10); |
||
453 | rtl8019Write(TCR, TCR_INIT); |
||
454 | |||
455 | if(resend) |
||
456 | rtl8019Write(CR, 0x26); |
||
457 | |||
458 | rtl8019Write(ISR, 0xFF); |
||
459 | } |
||
460 | |||
461 | |||
462 | void rtl8019RegDump(void) |
||
463 | { |
||
464 | // unsigned char result; |
||
465 | // result = rtl8019Read(TR); |
||
466 | |||
467 | // rprintf("Media State: "); |
||
468 | // if(!(result & AUTOD)) |
||
469 | // rprintf("Autonegotiation\r\n"); |
||
470 | // else if(result & RST_B) |
||
471 | // rprintf("PHY in Reset \r\n"); |
||
472 | // else if(!(result & RST_10B)) |
||
473 | // rprintf("10BASE-T \r\n"); |
||
474 | // else if(!(result & RST_TXB)) |
||
475 | // rprintf("100BASE-T \r\n"); |
||
476 | |||
477 | //rprintf("TR regsiter : %x\r\n",result); |
||
478 | //result = read_mii(0x10,0); |
||
479 | //rprintf("MII regsiter 0x10: %x\r\n",result); |
||
480 | |||
481 | rprintf("Page0: CR BNRY PSR PST ISR TSR RSR MMR TR GPI\r\n"); |
||
482 | rprintfProgStrM(" "); |
||
483 | rprintfu08(rtl8019Read(CR)); |
||
484 | rprintfProgStrM(" "); |
||
485 | rprintfu08(rtl8019Read(BNRY)); |
||
486 | rprintfProgStrM(" "); |
||
487 | rprintfu08(rtl8019Read(PSTART)); |
||
488 | rprintfProgStrM(" "); |
||
489 | rprintfu08(rtl8019Read(PSTOP)); |
||
490 | rprintfProgStrM(" "); |
||
491 | rprintfu08(rtl8019Read(ISR)); |
||
492 | rprintfProgStrM(" "); |
||
493 | rprintfu08(rtl8019Read(TSR)); |
||
494 | rprintfProgStrM(" "); |
||
495 | rprintfu08(rtl8019Read(RSR)); |
||
496 | rprintfProgStrM(" "); |
||
497 | // rprintfu08(rtl8019Read(MEMR)); |
||
498 | rprintfProgStrM(" "); |
||
499 | // rprintfu08(rtl8019Read(TR)); |
||
500 | rprintfProgStrM(" "); |
||
501 | // rprintfu08(rtl8019Read(GPI)); |
||
502 | rprintfCRLF(); |
||
503 | |||
504 | rtl8019Write(CR,rtl8019Read(CR)|PS0); |
||
505 | |||
506 | rprintf("Page1: CR PAR CPR\r\n"); |
||
507 | rprintfProgStrM(" "); |
||
508 | rprintfu08(rtl8019Read(CR)); |
||
509 | rprintfProgStrM(" "); |
||
510 | rprintfChar(rtl8019Read(PAR0)); |
||
511 | rprintfChar(rtl8019Read(PAR1)); |
||
512 | rprintfChar(rtl8019Read(PAR2)); |
||
513 | rprintfChar(rtl8019Read(PAR3)); |
||
514 | rprintfChar(rtl8019Read(PAR4)); |
||
515 | rprintfChar(rtl8019Read(PAR5)); |
||
516 | rprintfProgStrM(" "); |
||
517 | rprintfu08(rtl8019Read(CPR)); |
||
518 | |||
519 | rtl8019Write(CR,rtl8019Read(CR)&~PS0); |
||
520 | |||
521 | delay_ms(25); |
||
522 | } |
||
523 |
Powered by WebSVN v2.8.3