]> git.sur5r.net Git - freertos/blob - Demo/uIP_Demo_Rowley_ARM7/uip/cs8900a.c
First version under SVN is V4.0.1
[freertos] / Demo / uIP_Demo_Rowley_ARM7 / uip / cs8900a.c
1 // cs8900a.c: device driver for the CS8900a chip in 8-bit mode.\r
2 \r
3 #include <targets/LPC210x.h>\r
4 \r
5 #include "cs8900a.h"\r
6 #include "uip.h"\r
7 #include "uip_arp.h"\r
8 \r
9 #define IOR                  (1<<12)          // CS8900's ISA-bus interface pins\r
10 #define IOW                  (1<<13)\r
11 \r
12 // definitions for Crystal CS8900 ethernet-controller\r
13 // based on linux-header by Russel Nelson\r
14 \r
15 #define PP_ChipID            0x0000          // offset 0h -> Corp-ID\r
16                      \r
17                                                                                          // offset 2h -> Model/Product Number\r
18 #define LED_RED (1<<8)\r
19 #define LED_GREEN (1<<10)\r
20 #define LED_YELLOW (1<<11)\r
21 \r
22 #define PP_ISAIOB            0x0020          // IO base address\r
23 #define PP_CS8900_ISAINT     0x0022          // ISA interrupt select\r
24 #define PP_CS8900_ISADMA     0x0024          // ISA Rec DMA channel\r
25 #define PP_ISASOF            0x0026          // ISA DMA offset\r
26 #define PP_DmaFrameCnt       0x0028          // ISA DMA Frame count\r
27 #define PP_DmaByteCnt        0x002A          // ISA DMA Byte count\r
28 #define PP_CS8900_ISAMemB    0x002C          // Memory base\r
29 #define PP_ISABootBase       0x0030          // Boot Prom base\r
30 #define PP_ISABootMask       0x0034          // Boot Prom Mask\r
31 \r
32 // EEPROM data and command registers\r
33 #define PP_EECMD             0x0040          // NVR Interface Command register\r
34 #define PP_EEData            0x0042          // NVR Interface Data Register\r
35 \r
36 // Configuration and control registers\r
37 #define PP_RxCFG             0x0102          // Rx Bus config\r
38 #define PP_RxCTL             0x0104          // Receive Control Register\r
39 #define PP_TxCFG             0x0106          // Transmit Config Register\r
40 #define PP_TxCMD             0x0108          // Transmit Command Register\r
41 #define PP_BufCFG            0x010A          // Bus configuration Register\r
42 #define PP_LineCTL           0x0112          // Line Config Register\r
43 #define PP_SelfCTL           0x0114          // Self Command Register\r
44 #define PP_BusCTL            0x0116          // ISA bus control Register\r
45 #define PP_TestCTL           0x0118          // Test Register\r
46 \r
47 // Status and Event Registers\r
48 #define PP_ISQ               0x0120          // Interrupt Status\r
49 #define PP_RxEvent           0x0124          // Rx Event Register\r
50 #define PP_TxEvent           0x0128          // Tx Event Register\r
51 #define PP_BufEvent          0x012C          // Bus Event Register\r
52 #define PP_RxMiss            0x0130          // Receive Miss Count\r
53 #define PP_TxCol             0x0132          // Transmit Collision Count\r
54 #define PP_LineST            0x0134          // Line State Register\r
55 #define PP_SelfST            0x0136          // Self State register\r
56 #define PP_BusST             0x0138          // Bus Status\r
57 #define PP_TDR               0x013C          // Time Domain Reflectometry\r
58 \r
59 // Initiate Transmit Registers\r
60 #define PP_TxCommand         0x0144          // Tx Command\r
61 #define PP_TxLength          0x0146          // Tx Length\r
62 \r
63 // Adress Filter Registers\r
64 #define PP_LAF               0x0150          // Hash Table\r
65 #define PP_IA                0x0158          // Physical Address Register\r
66 \r
67 // Frame Location\r
68 #define PP_RxStatus          0x0400          // Receive start of frame\r
69 #define PP_RxLength          0x0402          // Receive Length of frame\r
70 #define PP_RxFrame           0x0404          // Receive frame pointer\r
71 #define PP_TxFrame           0x0A00          // Transmit frame pointer\r
72 \r
73 // Primary I/O Base Address. If no I/O base is supplied by the user, then this\r
74 // can be used as the default I/O base to access the PacketPage Area.\r
75 #define DEFAULTIOBASE        0x0300\r
76 \r
77 // PP_RxCFG - Receive  Configuration and Interrupt Mask bit definition - Read/write\r
78 #define SKIP_1               0x0040\r
79 #define RX_STREAM_ENBL       0x0080\r
80 #define RX_OK_ENBL           0x0100\r
81 #define RX_DMA_ONLY          0x0200\r
82 #define AUTO_RX_DMA          0x0400\r
83 #define BUFFER_CRC           0x0800\r
84 #define RX_CRC_ERROR_ENBL    0x1000\r
85 #define RX_RUNT_ENBL         0x2000\r
86 #define RX_EXTRA_DATA_ENBL   0x4000\r
87 \r
88 // PP_RxCTL - Receive Control bit definition - Read/write\r
89 #define RX_IA_HASH_ACCEPT    0x0040\r
90 #define RX_PROM_ACCEPT       0x0080\r
91 #define RX_OK_ACCEPT         0x0100\r
92 #define RX_MULTCAST_ACCEPT   0x0200\r
93 #define RX_IA_ACCEPT         0x0400\r
94 #define RX_BROADCAST_ACCEPT  0x0800\r
95 #define RX_BAD_CRC_ACCEPT    0x1000\r
96 #define RX_RUNT_ACCEPT       0x2000\r
97 #define RX_EXTRA_DATA_ACCEPT 0x4000\r
98 \r
99 // PP_TxCFG - Transmit Configuration Interrupt Mask bit definition - Read/write\r
100 #define TX_LOST_CRS_ENBL     0x0040\r
101 #define TX_SQE_ERROR_ENBL    0x0080\r
102 #define TX_OK_ENBL           0x0100\r
103 #define TX_LATE_COL_ENBL     0x0200\r
104 #define TX_JBR_ENBL          0x0400\r
105 #define TX_ANY_COL_ENBL      0x0800\r
106 #define TX_16_COL_ENBL       0x8000\r
107 \r
108 // PP_TxCMD - Transmit Command bit definition - Read-only and\r
109 // PP_TxCommand - Write-only\r
110 #define TX_START_5_BYTES     0x0000\r
111 #define TX_START_381_BYTES   0x0040\r
112 #define TX_START_1021_BYTES  0x0080\r
113 #define TX_START_ALL_BYTES   0x00C0\r
114 #define TX_FORCE             0x0100\r
115 #define TX_ONE_COL           0x0200\r
116 #define TX_NO_CRC            0x1000\r
117 #define TX_RUNT              0x2000\r
118 \r
119 // PP_BufCFG - Buffer Configuration Interrupt Mask bit definition - Read/write\r
120 #define GENERATE_SW_INTERRUPT      0x0040\r
121 #define RX_DMA_ENBL                0x0080\r
122 #define READY_FOR_TX_ENBL          0x0100\r
123 #define TX_UNDERRUN_ENBL           0x0200\r
124 #define RX_MISS_ENBL               0x0400\r
125 #define RX_128_BYTE_ENBL           0x0800\r
126 #define TX_COL_COUNT_OVRFLOW_ENBL  0x1000\r
127 #define RX_MISS_COUNT_OVRFLOW_ENBL 0x2000\r
128 #define RX_DEST_MATCH_ENBL         0x8000\r
129 \r
130 // PP_LineCTL - Line Control bit definition - Read/write\r
131 #define SERIAL_RX_ON         0x0040\r
132 #define SERIAL_TX_ON         0x0080\r
133 #define AUI_ONLY             0x0100\r
134 #define AUTO_AUI_10BASET     0x0200\r
135 #define MODIFIED_BACKOFF     0x0800\r
136 #define NO_AUTO_POLARITY     0x1000\r
137 #define TWO_PART_DEFDIS      0x2000\r
138 #define LOW_RX_SQUELCH       0x4000\r
139 \r
140 // PP_SelfCTL - Software Self Control bit definition - Read/write\r
141 #define POWER_ON_RESET       0x0040\r
142 #define SW_STOP              0x0100\r
143 #define SLEEP_ON             0x0200\r
144 #define AUTO_WAKEUP          0x0400\r
145 #define HCB0_ENBL            0x1000\r
146 #define HCB1_ENBL            0x2000\r
147 #define HCB0                 0x4000\r
148 #define HCB1                 0x8000\r
149 \r
150 // PP_BusCTL - ISA Bus Control bit definition - Read/write\r
151 #define RESET_RX_DMA         0x0040\r
152 #define MEMORY_ON            0x0400\r
153 #define DMA_BURST_MODE       0x0800\r
154 #define IO_CHANNEL_READY_ON  0x1000\r
155 #define RX_DMA_SIZE_64K      0x2000\r
156 #define ENABLE_IRQ           0x8000\r
157 \r
158 // PP_TestCTL - Test Control bit definition - Read/write\r
159 #define LINK_OFF             0x0080\r
160 #define ENDEC_LOOPBACK       0x0200\r
161 #define AUI_LOOPBACK         0x0400\r
162 #define BACKOFF_OFF          0x0800\r
163 #define FDX_8900             0x4000\r
164 \r
165 // PP_RxEvent - Receive Event Bit definition - Read-only\r
166 #define RX_IA_HASHED         0x0040\r
167 #define RX_DRIBBLE           0x0080\r
168 #define RX_OK                0x0100\r
169 #define RX_HASHED            0x0200\r
170 #define RX_IA                0x0400\r
171 #define RX_BROADCAST         0x0800\r
172 #define RX_CRC_ERROR         0x1000\r
173 #define RX_RUNT              0x2000\r
174 #define RX_EXTRA_DATA        0x4000\r
175 #define HASH_INDEX_MASK      0xFC00          // Hash-Table Index Mask (6 Bit)\r
176 \r
177 // PP_TxEvent - Transmit Event Bit definition - Read-only\r
178 #define TX_LOST_CRS          0x0040\r
179 #define TX_SQE_ERROR         0x0080\r
180 #define TX_OK                0x0100\r
181 #define TX_LATE_COL          0x0200\r
182 #define TX_JBR               0x0400\r
183 #define TX_16_COL            0x8000\r
184 #define TX_COL_COUNT_MASK    0x7800\r
185 \r
186 // PP_BufEvent - Buffer Event Bit definition - Read-only\r
187 #define SW_INTERRUPT         0x0040\r
188 #define RX_DMA               0x0080\r
189 #define READY_FOR_TX         0x0100\r
190 #define TX_UNDERRUN          0x0200\r
191 #define RX_MISS              0x0400\r
192 #define RX_128_BYTE          0x0800\r
193 #define TX_COL_OVRFLW        0x1000\r
194 #define RX_MISS_OVRFLW       0x2000\r
195 #define RX_DEST_MATCH        0x8000\r
196 \r
197 // PP_LineST - Ethernet Line Status bit definition - Read-only\r
198 #define LINK_OK              0x0080\r
199 #define AUI_ON               0x0100\r
200 #define TENBASET_ON          0x0200\r
201 #define POLARITY_OK          0x1000\r
202 #define CRS_OK               0x4000\r
203 \r
204 // PP_SelfST - Chip Software Status bit definition\r
205 #define ACTIVE_33V           0x0040\r
206 #define INIT_DONE            0x0080\r
207 #define SI_BUSY              0x0100\r
208 #define EEPROM_PRESENT       0x0200\r
209 #define EEPROM_OK            0x0400\r
210 #define EL_PRESENT           0x0800\r
211 #define EE_SIZE_64           0x1000\r
212 \r
213 // PP_BusST - ISA Bus Status bit definition\r
214 #define TX_BID_ERROR         0x0080\r
215 #define READY_FOR_TX_NOW     0x0100\r
216 \r
217 // The following block defines the ISQ event types\r
218 #define ISQ_RX_EVENT         0x0004\r
219 #define ISQ_TX_EVENT         0x0008\r
220 #define ISQ_BUFFER_EVENT     0x000C\r
221 #define ISQ_RX_MISS_EVENT    0x0010\r
222 #define ISQ_TX_COL_EVENT     0x0012\r
223 \r
224 #define ISQ_EVENT_MASK       0x003F          // ISQ mask to find out type of event\r
225 \r
226 // Ports for I/O-Mode\r
227 #define RX_FRAME_PORT        0x0000\r
228 #define TX_FRAME_PORT        0x0000\r
229 #define TX_CMD_PORT          0x0004\r
230 #define TX_LEN_PORT          0x0006\r
231 #define ISQ_PORT             0x0008\r
232 #define ADD_PORT             0x000A\r
233 #define DATA_PORT            0x000C\r
234 \r
235 #define AUTOINCREMENT        0x8000          // Bit mask to set Bit-15 for autoincrement\r
236 \r
237 // EEProm Commands\r
238 #define EEPROM_WRITE_EN      0x00F0\r
239 #define EEPROM_WRITE_DIS     0x0000\r
240 #define EEPROM_WRITE_CMD     0x0100\r
241 #define EEPROM_READ_CMD      0x0200\r
242 \r
243 // Receive Header of each packet in receive area of memory for DMA-Mode\r
244 #define RBUF_EVENT_LOW       0x0000          // Low byte of RxEvent\r
245 #define RBUF_EVENT_HIGH      0x0001          // High byte of RxEvent\r
246 #define RBUF_LEN_LOW         0x0002          // Length of received data - low byte\r
247 #define RBUF_LEN_HI          0x0003          // Length of received data - high byte\r
248 #define RBUF_HEAD_LEN        0x0004          // Length of this header\r
249 \r
250 // typedefs\r
251 typedef struct {                             // struct to store CS8900's\r
252   unsigned int Addr;                         // init-sequence\r
253   unsigned int Data;\r
254 } TInitSeq;\r
255 \r
256 unsigned short ticks;\r
257 \r
258 static void skip_frame(void);\r
259 \r
260 const TInitSeq InitSeq[] =\r
261 {\r
262   PP_IA,       UIP_ETHADDR0 + (UIP_ETHADDR1 << 8),     // set our MAC as Individual Address\r
263   PP_IA + 2,   UIP_ETHADDR2 + (UIP_ETHADDR3 << 8),\r
264   PP_IA + 4,   UIP_ETHADDR4 + (UIP_ETHADDR5 << 8),\r
265   PP_LineCTL,  SERIAL_RX_ON | SERIAL_TX_ON,           // configure the Physical Interface\r
266   PP_RxCTL,    RX_OK_ACCEPT | RX_IA_ACCEPT | RX_BROADCAST_ACCEPT\r
267 };\r
268 \r
269 // Writes a word in little-endian byte order to a specified port-address\r
270 void\r
271 cs8900a_write(unsigned addr, unsigned int data)\r
272 {\r
273   IODIR |= 0xff << 16;                           // Data port to output\r
274 \r
275   IOCLR = 0xf << 4;                              // Put address on bus\r
276   IOSET = addr << 4;\r
277   \r
278   IOCLR = 0xff << 16;                            // Write low order byte to data bus\r
279   IOSET = data << 16;\r
280 \r
281   IOCLR = IOW;                                   // Toggle IOW-signal\r
282   IOSET = IOW;\r
283 \r
284   IOCLR = 0xf << 4;\r
285   IOSET = ((addr | 1) << 4);                     // And put next address on bus\r
286 \r
287   IOCLR = 0xff << 16;                            // Write high order byte to data bus\r
288   IOSET = data >> 8 << 16;\r
289 \r
290   IOCLR = IOW;                                   // Toggle IOW-signal\r
291   IOSET = IOW;\r
292 }\r
293 \r
294 // Reads a word in little-endian byte order from a specified port-address\r
295 unsigned\r
296 cs8900a_read(unsigned addr)\r
297 {\r
298   unsigned int value;\r
299 \r
300   IODIR &= ~(0xff << 16);                        // Data port to input\r
301 \r
302   IOCLR = 0xf << 4;                              // Put address on bus\r
303   IOSET = addr << 4;\r
304 \r
305   IOCLR = IOR;                                   // IOR-signal low\r
306   value = (IOPIN >> 16) & 0xff;                  // get low order byte from data bus\r
307   IOSET = IOR;\r
308 \r
309   IOSET = 1 << 4;                                // IOR high and put next address on bus\r
310 \r
311   IOCLR = IOR;                                   // IOR-signal low\r
312   value |= ((IOPIN >> 8) & 0xff00);              // get high order byte from data bus\r
313   IOSET = IOR;                                   // IOR-signal low\r
314   \r
315   return value;\r
316 }\r
317 \r
318 // Reads a word in little-endian byte order from a specified port-address\r
319 unsigned\r
320 cs8900a_read_addr_high_first(unsigned addr)\r
321 {\r
322   unsigned int value;\r
323 \r
324   IODIR &= ~(0xff << 16);                        // Data port to input\r
325 \r
326   IOCLR = 0xf << 4;                              // Put address on bus\r
327   IOSET = (addr+1) << 4;\r
328 \r
329   IOCLR = IOR;                                   // IOR-signal low\r
330   value = ((IOPIN >> 8) & 0xff00);               // get high order byte from data bus\r
331   IOSET = IOR;                                   // IOR-signal high\r
332 \r
333   IOCLR = 1 << 4;                                // Put low address on bus\r
334 \r
335   IOCLR = IOR;                                   // IOR-signal low\r
336   value |= (IOPIN >> 16) & 0xff;                 // get low order byte from data bus\r
337   IOSET = IOR;\r
338 \r
339   return value;\r
340 }\r
341 \r
342 void\r
343 cs8900a_init(void)\r
344 {\r
345   int i;\r
346 \r
347   // Reset outputs, control lines high\r
348   IOSET = IOR | IOW;\r
349 \r
350   // No LEDs on.\r
351   IOSET = LED_RED | LED_YELLOW | LED_GREEN;\r
352 \r
353   // Port 3 as output (all pins but RS232)\r
354   IODIR = ~0U; // everything to output.\r
355 \r
356   // Reset outputs\r
357   IOCLR = 0xff << 16;  // clear data outputs\r
358 \r
359   // Reset the CS8900A\r
360   cs8900a_write(ADD_PORT, PP_SelfCTL);\r
361   cs8900a_write(DATA_PORT, POWER_ON_RESET);\r
362 \r
363   // Wait until chip-reset is done\r
364   cs8900a_write(ADD_PORT, PP_SelfST);\r
365   while ((cs8900a_read(DATA_PORT) & INIT_DONE) == 0)\r
366     ;\r
367 \r
368   // Configure the CS8900A\r
369   for (i = 0; i < sizeof InitSeq / sizeof (TInitSeq); ++i)\r
370     {\r
371       cs8900a_write(ADD_PORT, InitSeq[i].Addr);\r
372       cs8900a_write(DATA_PORT, InitSeq[i].Data);\r
373     }\r
374 }\r
375 \r
376 void\r
377 cs8900a_send(void)\r
378 {\r
379   unsigned u;\r
380 \r
381   IOCLR = LED_RED;  // Light RED LED when frame starting\r
382 \r
383   // Transmit command\r
384   cs8900a_write(TX_CMD_PORT, TX_START_ALL_BYTES);\r
385   cs8900a_write(TX_LEN_PORT, uip_len);\r
386 \r
387   // Maximum number of retries\r
388   u = 8;\r
389   for (;;)\r
390     {\r
391       // Check for avaliable buffer space\r
392       cs8900a_write(ADD_PORT, PP_BusST);\r
393       if (cs8900a_read(DATA_PORT) & READY_FOR_TX_NOW)\r
394         break;\r
395       if (u -- == 0)\r
396         {\r
397           IOSET = LED_RED;  // Extinguish RED LED on end of frame\r
398           return;\r
399         }\r
400 \r
401       // No space avaliable, skip a received frame and try again\r
402       skip_frame();\r
403     }\r
404 \r
405   IODIR |= 0xff << 16;                           // Data port to output\r
406 \r
407   // Send 40+14=54 bytes of header\r
408   for (u = 0; u < 54; u += 2)\r
409     {\r
410       IOCLR = 0xf << 4;                              // Put address on bus\r
411       IOSET = TX_FRAME_PORT << 4;\r
412 \r
413       IOCLR = 0xff << 16;                            // Write low order byte to data bus\r
414       IOSET = uip_buf[u] << 16;                      // write low order byte to data bus\r
415 \r
416       IOCLR = IOW;                                   // Toggle IOW-signal\r
417       IOSET = IOW;\r
418 \r
419       IOCLR = 0xf << 4;                              // Put address on bus\r
420       IOSET = (TX_FRAME_PORT | 1) << 4;              // and put next address on bus\r
421 \r
422       IOCLR = 0xff << 16;                            // Write low order byte to data bus\r
423       IOSET = uip_buf[u+1] << 16;                    // write low order byte to data bus\r
424 \r
425       IOCLR = IOW;                                   // Toggle IOW-signal\r
426       IOSET = IOW;\r
427     }\r
428 \r
429   if (uip_len <= 54)\r
430     {\r
431       IOSET = LED_RED;  // Extinguish RED LED on end of frame\r
432       return;\r
433     }\r
434 \r
435   // Send remainder of packet, the application data\r
436   uip_len -= 54;\r
437   for (u = 0; u < uip_len; u += 2)\r
438     {\r
439 \r
440       IOCLR = 0xf << 4;                          // Put address on bus\r
441       IOSET = TX_FRAME_PORT << 4;\r
442 \r
443       IOCLR = 0xff << 16;                        // Write low order byte to data bus\r
444       IOSET = uip_appdata[u] << 16;              // write low order byte to data bus\r
445 \r
446       IOCLR = IOW;                               // Toggle IOW-signal\r
447       IOSET = IOW;\r
448 \r
449       IOCLR = 0xf << 4;                          // Put address on bus\r
450       IOSET = (TX_FRAME_PORT | 1) << 4;          // and put next address on bus\r
451 \r
452       IOCLR = 0xff << 16;                        // Write low order byte to data bus\r
453       IOSET = uip_appdata[u+1] << 16;            // write low order byte to data bus\r
454 \r
455       IOCLR = IOW;                               // Toggle IOW-signal\r
456       IOSET = IOW;\r
457     }\r
458 \r
459   IOSET = LED_RED;  // Extinguish RED LED on end of frame\r
460 }\r
461 \r
462 static void\r
463 skip_frame(void)\r
464 {\r
465   // No space avaliable, skip a received frame and try again\r
466   cs8900a_write(ADD_PORT, PP_RxCFG);\r
467   cs8900a_write(DATA_PORT, cs8900a_read(DATA_PORT) | SKIP_1);\r
468 }\r
469 \r
470 u8_t\r
471 cs8900a_poll(void)\r
472 {\r
473   u16_t len, u;\r
474 \r
475   // Check receiver event register to see if there are any valid frames avaliable\r
476   cs8900a_write(ADD_PORT, PP_RxEvent);\r
477   if ((cs8900a_read(DATA_PORT) & 0xd00) == 0)\r
478     return 0;\r
479 \r
480   IOCLR = LED_GREEN;  // Light GREED LED when frame coming in.\r
481 \r
482   // Read receiver status and discard it.\r
483   cs8900a_read_addr_high_first(RX_FRAME_PORT);\r
484 \r
485   // Read frame length\r
486   len = cs8900a_read_addr_high_first(RX_FRAME_PORT);\r
487 \r
488   // If the frame is too big to handle, throw it away\r
489   if (len > UIP_BUFSIZE)\r
490     {\r
491       skip_frame();\r
492       return 0;\r
493     }\r
494 \r
495   // Data port to input\r
496   IODIR &= ~(0xff << 16);\r
497 \r
498   IOCLR = 0xf << 4;                          // put address on bus\r
499   IOSET = RX_FRAME_PORT << 4; \r
500 \r
501   // Read bytes into uip_buf\r
502   u = 0;\r
503   while (u < len)\r
504     {\r
505       IOCLR = 1 << 4;                            // put address on bus\r
506 \r
507       IOCLR = IOR;                               // IOR-signal low\r
508       uip_buf[u] = IOPIN >> 16;                // get high order byte from data bus\r
509       IOSET = IOR;                               // IOR-signal high\r
510 \r
511       IOSET = 1 << 4;                            // put address on bus\r
512 \r
513       IOCLR = IOR;                               // IOR-signal low\r
514       uip_buf[u+1] = IOPIN >> 16;                  // get high order byte from data bus\r
515       IOSET = IOR;                               // IOR-signal high\r
516       u += 2;\r
517     }\r
518 \r
519   IOSET = LED_GREEN;  // Extinguish GREED LED when frame finished.\r
520   return len;\r
521 }\r
522 \r