comparison packages/devs/eth/arm/edb7xxx/current/src/if_edb7xxx.c @ 82:6736c52df507 ecos-sw-2000-04-14

Merge from eCos master repository on 2000-04-14-13:35:46-BST
author jlarmour
date Tue, 18 Apr 2000 21:51:55 +0000
parents
children 6ed91473a1cd
comparison
equal deleted inserted replaced
81:89fef2181d7d 82:6736c52df507
1 //==========================================================================
2 //
3 // dev/if_edb7xxx.c
4 //
5 // Ethernet device driver for Cirrus Logic EDB7xxx using CS8900
6 //
7 //==========================================================================
8 //####COPYRIGHTBEGIN####
9 //
10 // -------------------------------------------
11 // The contents of this file are subject to the Red Hat eCos Public License
12 // Version 1.1 (the "License"); you may not use this file except in
13 // compliance with the License. You may obtain a copy of the License at
14 // http://www.redhat.com/
15 //
16 // Software distributed under the License is distributed on an "AS IS"
17 // basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
18 // License for the specific language governing rights and limitations under
19 // the License.
20 //
21 // The Original Code is eCos - Embedded Configurable Operating System,
22 // released September 30, 1998.
23 //
24 // The Initial Developer of the Original Code is Red Hat.
25 // Portions created by Red Hat are
26 // Copyright (C) 1998, 1999, 2000 Red Hat, Inc.
27 // All Rights Reserved.
28 // -------------------------------------------
29 //
30 //####COPYRIGHTEND####
31 //####BSDCOPYRIGHTBEGIN####
32 //
33 // -------------------------------------------
34 //
35 // Portions of this software may have been derived from OpenBSD or other sources,
36 // and are covered by the appropriate copyright disclaimers included herein.
37 //
38 // -------------------------------------------
39 //
40 //####BSDCOPYRIGHTEND####
41 //==========================================================================
42 //#####DESCRIPTIONBEGIN####
43 //
44 // Author(s): gthomas
45 // Contributors: gthomas
46 // Date: 2000-01-10
47 // Purpose:
48 // Description: hardware driver for CS8900 ethernet
49 //
50 //
51 //####DESCRIPTIONEND####
52 //
53 //==========================================================================
54
55 // Ethernet device driver for Cirrus Logic EDB7xxx
56 // Based on CS8900A
57
58 #include <pkgconf/net.h>
59 #include <cyg/infra/cyg_type.h>
60 #include <cyg/hal/hal_arch.h>
61 #include <cyg/infra/diag.h>
62 #include <cyg/hal/drv_api.h>
63 #include <netdev.h>
64 #include <eth_drv.h>
65
66 #define INTS_DONT_WORK
67 #undef INTS_DONT_WORK
68
69 #ifdef INTS_DONT_WORK
70 #define STACK_SIZE CYGNUM_HAL_STACK_SIZE_MINIMUM
71 static char cs8900_fake_int_stack[STACK_SIZE];
72 static cyg_thread cs8900_fake_int_thread_data;
73 static cyg_handle_t cs8900_fake_int_thread_handle;
74 static void cs8900_fake_int(cyg_addrword_t);
75 #endif
76
77 #define CS8900_BASE 0x20000000
78 #include "cs8900.h"
79 #define ETHER_ADDR_LEN 6
80
81 extern int net_debug; // FIXME
82
83 struct cs8900_priv_data {
84 int txbusy; // A packet has been sent
85 unsigned long txkey; // Used to ack when packet sent
86 } _cs8900_priv_data;
87
88 ETH_DRV_SC(edb7xxx_sc,
89 &_cs8900_priv_data, // Driver specific data
90 "eth0", // Name for this interface
91 cs8900_start,
92 cs8900_stop,
93 cs8900_control,
94 cs8900_can_send,
95 cs8900_send,
96 cs8900_recv);
97
98 NETDEVTAB_ENTRY(edb7xxx_netdev,
99 "edb7xxx",
100 edb7xxx_cs8900_init,
101 &edb7xxx_sc);
102
103 // FIXME
104 static unsigned char enaddr[] = { 0x08, 0x88, 0x12, 0x34, 0x56, 0x78};
105
106 static void cs8900_int(struct eth_drv_sc *sc);
107 static cyg_interrupt cs8900_interrupt;
108 static cyg_handle_t cs8900_interrupt_handle;
109
110 // This ISR is called when the ethernet interrupt occurs
111 static int
112 cs8900_isr(cyg_vector_t vector, cyg_addrword_t data, HAL_SavedRegisters *regs)
113 {
114 cyg_drv_interrupt_mask(CYGNUM_HAL_INTERRUPT_EINT3);
115 return (CYG_ISR_HANDLED|CYG_ISR_CALL_DSR); // Run the DSR
116 }
117
118 // This DSR handles the ethernet [logical] processing
119 static void
120 cs8900_dsr(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
121 {
122 cs8900_int((struct eth_drv_sc *)data);
123 // Allow interrupts to happen again
124 cyg_drv_interrupt_acknowledge(CYGNUM_HAL_INTERRUPT_EINT3);
125 cyg_drv_interrupt_unmask(CYGNUM_HAL_INTERRUPT_EINT3);
126 }
127
128 static bool
129 edb7xxx_cs8900_init(struct cyg_netdevtab_entry *tab)
130 {
131 struct eth_drv_sc *sc = (struct eth_drv_sc *)tab->device_instance;
132 unsigned short chip_type, chip_rev, chip_status;
133 int i;
134
135 diag_printf("cs8900 init\n");
136
137 // Initialize environment, setup interrupt handler
138 cyg_drv_interrupt_create(CYGNUM_HAL_INTERRUPT_EINT3,
139 99, // Priority - what goes here?
140 (cyg_addrword_t)sc, // Data item passed to interrupt handler
141 (cyg_ISR_t *)cs8900_isr,
142 (cyg_DSR_t *)cs8900_dsr,
143 &cs8900_interrupt_handle,
144 &cs8900_interrupt);
145 cyg_drv_interrupt_attach(cs8900_interrupt_handle);
146 cyg_drv_interrupt_acknowledge(CYGNUM_HAL_INTERRUPT_EINT3);
147 cyg_drv_interrupt_unmask(CYGNUM_HAL_INTERRUPT_EINT3);
148
149 #ifdef INTS_DONT_WORK
150 cyg_thread_create(1, // Priority
151 cs8900_fake_int, // entry
152 0, // entry parameter
153 "CS8900 int", // Name
154 &cs8900_fake_int_stack[0], // Stack
155 STACK_SIZE, // Size
156 &cs8900_fake_int_thread_handle, // Handle
157 &cs8900_fake_int_thread_data // Thread data structure
158 );
159 cyg_thread_resume(cs8900_fake_int_thread_handle); // Start it
160 #endif
161
162 chip_type = get_reg(PP_ChipID);
163 chip_rev = get_reg(PP_ChipRev);
164
165 diag_printf("CS8900 - type: %x, rev: %x\n", chip_type, chip_rev);
166
167 put_reg(PP_SelfCtl, PP_SelfCtl_Reset); // Reset chip
168 while ((get_reg(PP_SelfStat) & PP_SelfStat_InitD) == 0) ;
169
170 chip_status = get_reg(PP_SelfStat);
171 diag_printf("CS8900 - status: %x (%sEEPROM present)\n", chip_status,
172 chip_status&PP_SelfStat_EEPROM ? "" : "no ");
173
174 // Set up hardware address - FIXME
175 for (i = 0; i < ETHER_ADDR_LEN; i += 2) {
176 put_reg(PP_LAF+i, 0xFFFF);
177 put_reg(PP_IA+i, enaddr[i] | (enaddr[i+1] << 8));
178 }
179
180 // Initialize upper level driver
181 eth_drv_init(sc, enaddr);
182
183 return true;
184 }
185
186 static void
187 cs8900_stop(struct eth_drv_sc *sc)
188 {
189 put_reg(PP_SelfCtl, PP_SelfCtl_Reset); // Reset chip
190 while ((get_reg(PP_SelfStat) & PP_SelfStat_InitD) == 0) ;
191 }
192
193 //
194 // This function is called to "start up" the interface. It may be called
195 // multiple times, even when the hardware is already running. It will be
196 // called whenever something "hardware oriented" changes and should leave
197 // the hardware ready to send/receive packets.
198 //
199 static void
200 cs8900_start(struct eth_drv_sc *sc, unsigned char *enaddr, int flags)
201 {
202 unsigned short stat;
203 put_reg(PP_BusCtl, PP_BusCtl_MemoryE); // Disable interrupts, memory mode
204 put_reg(PP_IntReg, PP_IntReg_IRQ0); // Only possibility
205 put_reg(PP_RxCFG, PP_RxCFG_RxOK | PP_RxCFG_CRC |
206 PP_RxCFG_RUNT | PP_RxCFG_EXTRA);
207 put_reg(PP_RxCTL, PP_RxCTL_RxOK | PP_RxCTL_Broadcast |
208 PP_RxCTL_IA);
209 put_reg(PP_TxCFG, PP_TxCFG_TxOK | PP_TxCFG_Collision |
210 PP_TxCFG_CRS | PP_TxCFG_SQE | PP_TxCFG_Late |
211 PP_TxCFG_Jabber | PP_TxCFG_16Collisions);
212 put_reg(PP_BufCFG, PP_BufCFG_TxRDY | PP_BufCFG_TxUE | PP_BufCFG_RxMiss |
213 PP_BufCFG_TxCol | PP_BufCFG_Miss | PP_BufCFG_SWI);
214 put_reg(PP_IntReg, PP_IntReg_IRQ0); // Only possibility
215 put_reg(PP_LineCTL, PP_LineCTL_Rx | PP_LineCTL_Tx);
216 // Clear Interrupt Status Queue before enabling interrupts
217 while ((stat = CS8900_ISQ) != 0) ;
218 put_reg(PP_BusCtl, PP_BusCtl_EnableIRQ);
219 }
220
221 //
222 // This routine is called to perform special "control" opertions
223 //
224 static int
225 cs8900_control(struct eth_drv_sc *sc, unsigned long key,
226 void *data, int data_length)
227 {
228 switch (key) {
229 case ETH_DRV_SET_MAC_ADDRESS:
230 return 0;
231 break;
232 default:
233 return 1;
234 break;
235 }
236 }
237
238 //
239 // This routine is called to see if it is possible to send another packet.
240 // It will return non-zero if a transmit is possible, zero otherwise.
241 //
242 static int
243 cs8900_can_send(struct eth_drv_sc *sc)
244 {
245 struct cs8900_priv_data *cpd = (struct cs8900_priv_data *)sc->driver_private;
246 return (cpd->txbusy == 0);
247 }
248
249 //
250 // This routine is called to send data to the hardware.
251 static void
252 cs8900_send(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len,
253 int total_len, unsigned long key)
254 {
255 struct cs8900_priv_data *cpd = (struct cs8900_priv_data *)sc->driver_private;
256 int i;
257 int len;
258 unsigned char *data;
259 unsigned short saved_data = 0, *sdata;
260 unsigned short stat;
261 bool odd_byte = false;
262
263 // Mark xmitter busy
264 cpd->txbusy = 1;
265 cpd->txkey = key;
266 // Start the xmit sequence
267 // Note: this can go back once the 'dump' is removed
268 // CS8900_TxCMD = PP_TxCmd_TxStart_5; // Start more-or-less immediately
269 CS8900_TxCMD = PP_TxCmd_TxStart_Full; // Start only when all data sent to chip
270 CS8900_TxLEN = total_len;
271 stat = get_reg(PP_BusStat); // This actually starts the xmit
272
273 // Put data into buffer
274 for (i = 0; i < sg_len; i++) {
275 data = (unsigned char *)sg_list[i].buf;
276 len = sg_list[i].len;
277 if (len > 0) {
278 /* Finish the last word. */
279 if (odd_byte) {
280 saved_data |= (*data++ << 8);
281 CS8900_RTDATA = saved_data;
282 len--;
283 odd_byte = false;
284 }
285 /* Output contiguous words. */
286 sdata = (unsigned short *)data;
287 while (len > 1) {
288 CS8900_RTDATA = *sdata++;
289 len -= sizeof(unsigned short);
290 }
291 /* Save last byte, if necessary. */
292 if (len == 1) {
293 data = (unsigned char *)sdata;
294 saved_data = *data;
295 odd_byte = true;
296 }
297 }
298 }
299 if (odd_byte) {
300 CS8900_RTDATA = saved_data;
301 }
302 }
303
304 //
305 // This function is called when a packet has been received. It's job is
306 // to prepare to unload the packet from the hardware. Once the length of
307 // the packet is known, the upper layer of the driver can be told. When
308 // the upper layer is ready to unload the packet, the internal function
309 // 'cs8900_recv' will be called to actually fetch it from the hardware.
310 //
311 static void
312 cs8900_RxEvent(struct eth_drv_sc *sc)
313 {
314 unsigned short stat, len;
315
316 stat = CS8900_RTDATA;
317 len = CS8900_RTDATA;
318 if (net_debug) {
319 diag_printf("RxEvent - stat: %x, len: %d\n", stat, len);
320 }
321 eth_drv_recv(sc, len);
322 }
323
324 //
325 // This function is called as a result of the "eth_drv_recv()" call above.
326 // It's job is to actually fetch data for a packet from the hardware once
327 // memory buffers have been allocated for the packet. Note that the buffers
328 // may come in pieces, using a scatter-gather list. This allows for more
329 // efficient processing in the upper layers of the stack.
330 //
331 static void
332 cs8900_recv(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len)
333 {
334 int i, mlen;
335 unsigned short *data, val;
336 unsigned char *cp, cval;
337
338 for (i = 0; i < sg_len; i++) {
339 data = (unsigned short *)sg_list[i].buf;
340 mlen = sg_list[i].len;
341 while (mlen >= sizeof(*data)) {
342 val = CS8900_RTDATA;
343 if (data) {
344 *data++ = val;
345 }
346 mlen -= sizeof(*data);
347 }
348 if (mlen) {
349 // Fetch last odd byte
350 cval = CS8900_RTDATA & 0xFF;
351 if (cp = (unsigned char *)data) {
352 *cp = cval;
353 }
354 }
355 }
356 }
357
358 static void
359 cs8900_TxEvent(struct eth_drv_sc *sc, int stat)
360 {
361 struct cs8900_priv_data *cpd = (struct cs8900_priv_data *)sc->driver_private;
362 stat = get_reg(PP_TER);
363 if (net_debug) {
364 diag_printf("Tx event: %x\n", stat);
365 }
366 cpd->txbusy = 0;
367 eth_drv_tx_done(sc, cpd->txkey, 0);
368 }
369
370 static void
371 cs8900_BufEvent(struct eth_drv_sc *sc, int stat)
372 {
373 if (stat & PP_BufCFG_RxMiss) {
374 }
375 if (stat & PP_BufCFG_TxUE) {
376 }
377 }
378
379 static void
380 cs8900_int(struct eth_drv_sc *sc)
381 {
382 unsigned short event;
383 while ((event = CS8900_ISQ) != 0) {
384 switch (event & ISQ_EventMask) {
385 case ISQ_RxEvent:
386 cs8900_RxEvent(sc);
387 break;
388 case ISQ_TxEvent:
389 cs8900_TxEvent(sc, event);
390 break;
391 case ISQ_BufEvent:
392 cs8900_BufEvent(sc, event);
393 break;
394 case ISQ_RxMissEvent:
395 // Receive miss counter has overflowed
396 break;
397 case ISQ_TxColEvent:
398 // Transmit collision counter has overflowed
399 break;
400 default:
401 diag_printf("%s: Unknown event: %x\n", __FUNCTION__, event);
402 break;
403 }
404 }
405 }
406
407 #ifdef INTS_DONT_WORK
408 void
409 cs8900_fake_int(cyg_addrword_t param)
410 {
411 int s;
412 while (true) {
413 cyg_thread_delay(5);
414 s = splnet();
415 cs8900_int(&edb7xxx_sc);
416 splx(s);
417 }
418 }
419 #endif
420