]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - packages/devs/eth/frv/frv400/v2_0/include/devs_eth_frv400.inl
Initial revision
[karo-tx-redboot.git] / packages / devs / eth / frv / frv400 / v2_0 / include / devs_eth_frv400.inl
1 //==========================================================================
2 //
3 //      devs/eth/frv/frv400/..../include/devs_eth_frv400.inl
4 //
5 //      FRV400 ethernet I/O definitions.
6 //
7 //==========================================================================
8 //####ECOSGPLCOPYRIGHTBEGIN####
9 // -------------------------------------------
10 // This file is part of eCos, the Embedded Configurable Operating System.
11 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
12 //
13 // eCos is free software; you can redistribute it and/or modify it under
14 // the terms of the GNU General Public License as published by the Free
15 // Software Foundation; either version 2 or (at your option) any later version.
16 //
17 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
18 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
20 // for more details.
21 //
22 // You should have received a copy of the GNU General Public License along
23 // with eCos; if not, write to the Free Software Foundation, Inc.,
24 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
25 //
26 // As a special exception, if other files instantiate templates or use macros
27 // or inline functions from this file, or you compile this file and link it
28 // with other works to produce a work based on this file, this file does not
29 // by itself cause the resulting work to be covered by the GNU General Public
30 // License. However the source code for this file must still be made available
31 // in accordance with section (3) of the GNU General Public License.
32 //
33 // This exception does not invalidate any other reasons why a work based on
34 // this file might be covered by the GNU General Public License.
35 //
36 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
37 // at http://sources.redhat.com/ecos/ecos-license/
38 // -------------------------------------------
39 //####ECOSGPLCOPYRIGHTEND####
40 //==========================================================================
41 //#####DESCRIPTIONBEGIN####
42 //
43 // Author(s):    jskov, hmt, gthomas
44 // Contributors: jskov
45 // Date:         2001-02-28
46 // Purpose:      FRV400 ethernet defintions
47 //####DESCRIPTIONEND####
48 //==========================================================================
49
50 #include <cyg/hal/hal_intr.h>           // CYGNUM_HAL_INTERRUPT_ETHR
51 #include <cyg/hal/hal_if.h>
52 #include <cyg/io/pci.h>
53
54 #ifdef __WANT_CONFIG
55
56 #define CYGHWR_NS_DP83902A_PLF_RESET(_dp_)      \
57     CYG_MACRO_START                             \
58     cyg_uint8 _t;                               \
59     HAL_READ_UINT8(_dp_->reset, _t);            \
60     CYGACC_CALL_IF_DELAY_US(10);                \
61     HAL_WRITE_UINT8(_dp_->reset, _t);           \
62     CYGACC_CALL_IF_DELAY_US(10000);                \
63     CYG_MACRO_END
64
65 #define DP_IN(_b_, _o_, _d_)                                    \
66     CYG_MACRO_START                                             \
67     HAL_READ_UINT8(((cyg_addrword_t)(_b_)+(_o_))^0x03, (_d_));    \
68     CYG_MACRO_END
69
70 #define DP_OUT(_b_, _o_, _d_)                                   \
71     CYG_MACRO_START                                             \
72     HAL_WRITE_UINT8(((cyg_addrword_t)(_b_)+(_o_))^0x03, (_d_));   \
73     CYG_MACRO_END
74
75 #define DP_IN_DATA(_b_, _d_)                                    \
76     CYG_MACRO_START                                             \
77     HAL_READ_UINT16((cyg_addrword_t)(_b_)^0x02, (_d_));         \
78     CYG_MACRO_END
79
80 #define DP_OUT_DATA(_b_, _d_)                                   \
81     CYG_MACRO_START                                             \
82     HAL_WRITE_UINT16((cyg_addrword_t)(_b_)^0x02, (_d_));        \
83     CYG_MACRO_END
84
85 //#define CYGHWR_NS_DP83902A_PLF_16BIT_DATA
86 //#define CYGHWR_NS_DP83902A_PLF_BROKEN_TX_DMA
87
88 #endif // __WANT_CONFIG
89
90 #ifdef __WANT_DEVS
91
92 #if defined(CYGSEM_DEVS_ETH_FRV400_ETH0_SET_ESA) 
93 #if defined(CYGPKG_REDBOOT) 
94 #include <pkgconf/redboot.h>
95 #ifdef CYGSEM_REDBOOT_FLASH_CONFIG
96 #include <redboot.h>
97 #include <flash_config.h>
98 RedBoot_config_option("Network hardware address [MAC]",
99                       lan_esa,
100                       ALWAYS_ENABLED, true,
101                       CONFIG_ESA, 0
102     );
103 #endif  // CYGSEM_REDBOOT_FLASH_CONFIG
104 #endif  // CYGPKG_REDBOOT
105 #include <cyg/hal/hal_if.h>
106 #ifndef CONFIG_ESA
107 #define CONFIG_ESA 6
108 #endif
109 #endif
110
111 static cyg_bool
112 find_rtl8029_match_func( cyg_uint16 v, cyg_uint16 d, cyg_uint32 c, void *p )
113 {
114     return ((v == 0x10EC) && (d == 0x8029));
115 }
116
117 static void
118 _frv400_eth_init(dp83902a_priv_data_t *dp)
119 {
120     cyg_pci_device_id devid;
121     cyg_pci_device dev_info;
122 #if defined(CYGSEM_DEVS_ETH_FRV400_ETH0_SET_ESA) 
123     cyg_bool esa_ok;
124     unsigned char _esa[6];
125 #else
126     unsigned char prom[32];
127     int i;
128 #endif
129
130     devid = CYG_PCI_NULL_DEVID;
131     if (cyg_pci_find_matching( &find_rtl8029_match_func, NULL, &devid )) {
132         cyg_pci_get_device_info(devid, &dev_info);
133         cyg_pci_translate_interrupt(&dev_info, &dp->interrupt);
134         dp->base = (cyg_uint8 *)(dev_info.base_map[0] & ~1);
135         dp->data = dp->base + 0x10;
136         dp->reset = dp->base + 0x1F;
137         diag_printf("RTL8029 at %p, interrupt: %x\n", dp->base, dp->interrupt);
138 #if defined(CYGSEM_DEVS_ETH_FRV400_ETH0_SET_ESA) 
139         esa_ok = CYGACC_CALL_IF_FLASH_CFG_OP(CYGNUM_CALL_IF_FLASH_CFG_GET,         
140                                              "lan_esa", _esa, CONFIG_ESA);
141         if (esa_ok) {
142             memcpy(dp->esa, _esa, sizeof(_esa));
143         }
144 #else
145         // Read ESA from EEPROM
146         DP_OUT(dp->base, DP_DCR, 0x48);  // Bytewide access
147         DP_OUT(dp->base, DP_RBCH, 0);    // Remote byte count
148         DP_OUT(dp->base, DP_RBCL, 0);
149         DP_OUT(dp->base, DP_ISR, 0xFF);  // Clear any pending interrupts
150         DP_OUT(dp->base, DP_IMR, 0x00);  // Mask all interrupts 
151         DP_OUT(dp->base, DP_RCR, 0x20);  // Monitor
152         DP_OUT(dp->base, DP_TCR, 0x02);  // loopback
153         DP_OUT(dp->base, DP_RBCH, 32);   // Remote byte count
154         DP_OUT(dp->base, DP_RBCL, 0);
155         DP_OUT(dp->base, DP_RSAL, 0);    // Remote address
156         DP_OUT(dp->base, DP_RSAH, 0);
157         DP_OUT(dp->base, DP_CR, DP_CR_START|DP_CR_RDMA);  // Read data
158         for (i = 0;  i < 32;  i++) {
159             cyg_uint16 _val;
160             HAL_READ_UINT16(dp->data, _val);
161             prom[i] = _val;
162         }
163         // Set ESA into chip
164         DP_OUT(dp->base, DP_CR, DP_CR_NODMA | DP_CR_PAGE1);  // Select page 1
165         for (i = 0; i < 6; i++) {
166             DP_OUT(dp->base, DP_P1_PAR0+i, prom[i]);
167         }
168         DP_OUT(dp->base, DP_CR, DP_CR_NODMA | DP_CR_PAGE0);  // Select page 0
169 #endif
170     }
171 }
172
173 #define CYGHWR_NS_DP83902A_PLF_INIT(dp) _frv400_eth_init(dp)
174
175 #ifndef CYGINT_IO_ETH_INT_SUPPORT_REQUIRED
176 static void
177 _frv400_eth_int_clear(dp83902a_priv_data_t *dp)
178 {
179     cyg_drv_interrupt_acknowledge(dp->interrupt);
180 }
181
182 #define CYGHWR_NS_DP83902A_PLF_INT_CLEAR(dp) _frv400_eth_int_clear(dp)
183 #endif
184
185 #ifdef CYGPKG_DEVS_ETH_FRV400_ETH0
186
187 static dp83902a_priv_data_t dp83902a_eth0_priv_data = { 
188     base : (cyg_uint8*) 0,  //
189     data : (cyg_uint8*) 0,  // Filled in at runtime
190     reset: (cyg_uint8*) 0,  //
191     interrupt: 0,           //
192     tx_buf1: 0x40,          // 
193     tx_buf2: 0x48,          // Buffer layout - change with care
194     rx_buf_start: 0x50,     //
195     rx_buf_end: 0x80,       //
196 #ifdef CYGSEM_DEVS_ETH_FRV400_ETH0_SET_ESA
197     esa : CYGDAT_DEVS_ETH_FRV400_ETH0_ESA,
198     hardwired_esa : true,
199 #else
200     hardwired_esa : false,
201 #endif
202 };
203
204 ETH_DRV_SC(dp83902a_sc,
205            &dp83902a_eth0_priv_data, // Driver specific data
206            CYGDAT_DEVS_ETH_FRV400_ETH0_NAME,
207            dp83902a_start,
208            dp83902a_stop,
209            dp83902a_control,
210            dp83902a_can_send,
211            dp83902a_send,
212            dp83902a_recv,
213            dp83902a_deliver,     // "pseudoDSR" called from fast net thread
214            dp83902a_poll,        // poll function, encapsulates ISR and DSR
215            dp83902a_int_vector);
216
217 NETDEVTAB_ENTRY(dp83902a_netdev, 
218                 "dp83902a_" CYGDAT_DEVS_ETH_FRV400_ETH0_NAME,
219                 dp83902a_init, 
220                 &dp83902a_sc);
221
222
223 #ifdef CYGPKG_REDBOOT
224
225
226 #define EECS (0x80|(1<<3))
227 #define EESK (1<<2)
228 #define EEDI (1<<1)
229 #define EEDO (1<<0)
230 #define dprintf(x...) do { } while(0)
231
232
233 static int eeprom_cmd(dp83902a_priv_data_t *dp, int cmd, int cmd_len)
234 {
235         unsigned retval = 0;
236
237         DP_OUT(dp->base, 1, EECS);
238         CYGACC_CALL_IF_DELAY_US(2000);
239
240         dprintf("Enabled for %08x (%d bits)\n", cmd, cmd_len);
241
242         DP_OUT(dp->base, 1, EECS | EESK);
243         CYGACC_CALL_IF_DELAY_US(2000);
244
245         dprintf("Clock\n");
246
247         /* Shift the command bits out. */
248         do {
249                 short databit = (cmd & (1 << cmd_len)) ? EEDI : 0;
250                 unsigned char tmp, tmp2;
251                 DP_OUT(dp->base, 1, EECS | databit); 
252                 CYGACC_CALL_IF_DELAY_US(2000);
253                 dprintf("Bit %d ... ", !!(cmd&(1<<cmd_len)));
254                 DP_OUT(dp->base, 1, EECS | databit | EESK);
255                 CYGACC_CALL_IF_DELAY_US(2000);
256                 dprintf(" \b");
257                 DP_IN(dp->base, 0, tmp2);
258                 DP_IN(dp->base, 1, tmp);
259                 CYGACC_CALL_IF_DELAY_US(2000);
260                 retval = (retval << 1) | !!(tmp & EEDO);
261                 dprintf(" \b");
262                 dprintf("Got bit %d (%02x %02x)\n", retval & 1, tmp2, tmp);
263         } while (--cmd_len >= 0);
264         DP_OUT(dp->base, 1, EECS);
265         CYGACC_CALL_IF_DELAY_US(2000);
266         dprintf("Last enb...\n");
267
268         /* Terminate the EEPROM access. */
269         DP_OUT(dp->base, 1, 0x80);
270         CYGACC_CALL_IF_DELAY_US(2000);
271         dprintf("Bye. retval %x\n", retval);
272         return retval;
273 }
274
275 static void setmac(dp83902a_priv_data_t *dp, unsigned short *newmac)
276 {
277         unsigned char old_cr, old_ee;
278         int i;
279
280         DP_IN(dp->base, DP_CR, old_cr);
281         DP_OUT(dp->base, DP_CR, old_cr | 0xc0); // Select page 3.
282         CYGACC_CALL_IF_DELAY_US(2000);
283
284         DP_IN(dp->base, 1, old_ee);
285         DP_OUT(dp->base, 1, 0x80);
286         CYGACC_CALL_IF_DELAY_US(2000);
287
288         /* Write enable */
289         eeprom_cmd(dp, (4<<6) + (0x30), 8);
290
291         for (i=0; i<3; i++) {
292                 unsigned adr = i+1;
293                 /* Erase word */
294 //              eeprom_cmd(dp, (7<<6) + (adr), 8);
295                 /* Write word */
296                 eeprom_cmd(dp, (5<<22) + (adr<<16) + newmac[i], 24);
297         }
298
299         /* Write disable */
300         eeprom_cmd(dp, (4<<6), 8);
301
302 #if 0
303         unsigned long words[16];
304         for (i=0; i<15; i++) {
305                 unsigned long cmd = (6<<22) + (i<<16);
306                 words[i] = eeprom_cmd(dp, cmd /*6<<23 + (i<<16)*/, 24);
307         }
308
309         for (i=0; i<15; i++) {
310                 diag_printf("Words[%d] %08x\n", i, words[i]);
311         }
312 #endif
313         DP_OUT(dp->base, 1, old_ee);
314         CYGACC_CALL_IF_DELAY_US(2000);
315         DP_OUT(dp->base, DP_CR, old_cr);
316         CYGACC_CALL_IF_DELAY_US(2000);
317 }
318
319
320 #include <redboot.h>
321 static void do_setmac(int argc, char *argv[]);
322 RedBoot_cmd("setmac", 
323             "Set Ethernet MAC address", 
324             "<xx:xx:xx:xx:xx:xx>",
325             do_setmac
326     );
327
328 static void 
329 do_setmac(int argc, char *argv[])
330 {
331         unsigned char *mac = NULL;
332         unsigned char mac_nybble[12];
333         unsigned short mac_word[3];
334         int c, n;
335
336         if (!scan_opts(argc, argv, 1, NULL, 0, (void *)&mac,
337                        OPTION_ARG_TYPE_STR, "<MAC address>"))
338                 return;
339
340         if (!mac) {
341                 diag_printf("Must supply MAC address\n");
342                 return;
343         }
344         for (c=n=0; n<12; c++) {
345                 if (mac[c] == ':' && !((c+1) % 3))
346                         /* Colon in an allowed place */
347                         continue;
348
349                 if (mac[c] >= '0' && mac[c] <= '9')
350                         mac_nybble[n] = mac[c] - '0';
351                 else if (mac[c] >= 'A' && mac[c] <= 'F')
352                         mac_nybble[n] = mac[c] - 'A' + 10;
353                 else if (mac[c] >= 'a' && mac[c] <= 'f')
354                         mac_nybble[n] = mac[c] - 'a' + 10;
355                 else {
356                         diag_printf("Invalid MAC address bad char %x\n", mac[c]);
357                         return;
358                 }
359
360                 n++;
361         }
362         if (mac[c] || n!=12 || (mac_nybble[1]&1)) {
363                 diag_printf("Invalid MAC address\n");
364                 return;
365         }
366         mac_word[0] = (mac_nybble[2] << 12) |
367                       (mac_nybble[3] << 8) |
368                       (mac_nybble[0] << 4) |
369                       (mac_nybble[1]);
370         mac_word[1] = (mac_nybble[6] << 12) |
371                       (mac_nybble[7] << 8) |
372                       (mac_nybble[4] << 4) |
373                       (mac_nybble[5]);
374         mac_word[2] = (mac_nybble[10] << 12) |
375                       (mac_nybble[11] << 8) |
376                       (mac_nybble[8] << 4) |
377                       (mac_nybble[9]);
378
379         diag_printf("Setting MAC address...");
380
381         setmac(&dp83902a_eth0_priv_data, mac_word);
382         diag_printf("... done. Reset to take effect.\n");
383         return;
384 }
385 #endif /* CYGPKG_REDBOOT */
386 #endif // CYGPKG_DEVS_ETH_FRV400_ETH0
387
388 #endif // __WANT_DEVS
389
390 // --------------------------------------------------------------
391
392 // EOF devs_eth_frv400.inl