blob: 01ddf5ccba4c7a76b0535bfa53e3b7a9010cec8c [file] [log] [blame]
wdenkaffae2b2002-08-17 09:36:01 +00001/*
2 * MPC8260 FCC Fast Ethernet
3 *
4 * Copyright (c) 2000 MontaVista Software, Inc. Dan Malek (dmalek@jlc.net)
5 *
6 * (C) Copyright 2000 Sysgo Real-Time Solutions, GmbH <www.elinos.com>
7 * Marius Groeger <mgroeger@sysgo.de>
8 *
9 * See file CREDITS for list of people who contributed to this
10 * project.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License as
14 * published by the Free Software Foundation; either version 2 of
15 * the License, or (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
25 * MA 02111-1307 USA
26 */
27
28/*
29 * MPC8260 FCC Fast Ethernet
30 * Basic ET HW initialization and packet RX/TX routines
31 *
32 * This code will not perform the IO port configuration. This should be
33 * done in the iop_conf_t structure specific for the board.
34 *
35 * TODO:
36 * add a PHY driver to do the negotiation
37 * reflect negotiation results in FPSMR
38 * look for ways to configure the board specific stuff elsewhere, eg.
39 * config_xxx.h or the board directory
40 */
41
42#include <common.h>
43#include <asm/cpm_8260.h>
44#include <mpc8260.h>
45#include <net.h>
46#include <command.h>
47#include <config.h>
48
49#if defined(CONFIG_ETHER_ON_FCC) && (CONFIG_COMMANDS & CFG_CMD_NET)
50
51/*---------------------------------------------------------------------*/
52#if (CONFIG_ETHER_INDEX == 1)
53
54#define PROFF_ENET PROFF_FCC1
55#define CPM_CR_ENET_SBLOCK CPM_CR_FCC1_SBLOCK
56#define CPM_CR_ENET_SBLOCK CPM_CR_FCC1_SBLOCK
57#define CPM_CR_ENET_PAGE CPM_CR_FCC1_PAGE
58
59/*---------------------------------------------------------------------*/
60#elif (CONFIG_ETHER_INDEX == 2)
61
62#define PROFF_ENET PROFF_FCC2
63#define CPM_CR_ENET_SBLOCK CPM_CR_FCC2_SBLOCK
64#define CPM_CR_ENET_PAGE CPM_CR_FCC2_PAGE
65
66/*---------------------------------------------------------------------*/
67#elif (CONFIG_ETHER_INDEX == 3)
68
69#define PROFF_ENET PROFF_FCC3
70#define CPM_CR_ENET_SBLOCK CPM_CR_FCC3_SBLOCK
71#define CPM_CR_ENET_PAGE CPM_CR_FCC3_PAGE
72
73/*---------------------------------------------------------------------*/
74#else
75#error "FCC Ethernet not correctly defined"
76#endif
77/*---------------------------------------------------------------------*/
78
79/* Maximum input DMA size. Must be a should(?) be a multiple of 4. */
80#define PKT_MAXDMA_SIZE 1520
81
82/* The FCC stores dest/src/type, data, and checksum for receive packets. */
83#define PKT_MAXBUF_SIZE 1518
84#define PKT_MINBUF_SIZE 64
85
86/* Maximum input buffer size. Must be a multiple of 32. */
87#define PKT_MAXBLR_SIZE 1536
88
89#define TOUT_LOOP 1000000
90
91#define TX_BUF_CNT 2
92#ifdef __GNUC__
93static char txbuf[TX_BUF_CNT][PKT_MAXBLR_SIZE] __attribute__ ((aligned(8)));
94#else
95#error "txbuf must be 64-bit aligned"
96#endif
97
98static uint rxIdx; /* index of the current RX buffer */
99static uint txIdx; /* index of the current TX buffer */
100
101/*
102 * FCC Ethernet Tx and Rx buffer descriptors.
103 * Provide for Double Buffering
104 * Note: PKTBUFSRX is defined in net.h
105 */
106
107typedef volatile struct rtxbd {
108 cbd_t rxbd[PKTBUFSRX];
109 cbd_t txbd[TX_BUF_CNT];
110} RTXBD;
111
112/* Good news: the FCC supports external BDs! */
113#ifdef __GNUC__
114static RTXBD rtx __attribute__ ((aligned(8)));
115#else
116#error "rtx must be 64-bit aligned"
117#endif
118
119int eth_send(volatile void *packet, int length)
120{
121 int i;
122 int result = 0;
123
124 if (length <= 0) {
125 printf("fec: bad packet size: %d\n", length);
126 goto out;
127 }
128
129 for(i=0; rtx.txbd[txIdx].cbd_sc & BD_ENET_TX_READY; i++) {
130 if (i >= TOUT_LOOP) {
131 printf("fec: tx buffer not ready\n");
132 goto out;
133 }
134 }
135
136 rtx.txbd[txIdx].cbd_bufaddr = (uint)packet;
137 rtx.txbd[txIdx].cbd_datlen = length;
138 rtx.txbd[txIdx].cbd_sc |= (BD_ENET_TX_READY | BD_ENET_TX_LAST |
139 BD_ENET_TX_WRAP);
140
141 for(i=0; rtx.txbd[txIdx].cbd_sc & BD_ENET_TX_READY; i++) {
142 if (i >= TOUT_LOOP) {
143 printf("fec: tx error\n");
144 goto out;
145 }
146 }
147
148#ifdef ET_DEBUG
149 printf("cycles: %d status: %04x\n", i, rtx.txbd[txIdx].cbd_sc);
150#endif
151
152 /* return only status bits */
153 result = rtx.txbd[txIdx].cbd_sc & BD_ENET_TX_STATS;
154
155out:
156 return result;
157}
158
159int eth_rx(void)
160{
161 int length;
162
163 for (;;)
164 {
165 if (rtx.rxbd[rxIdx].cbd_sc & BD_ENET_RX_EMPTY) {
166 length = -1;
167 break; /* nothing received - leave for() loop */
168 }
169 length = rtx.rxbd[rxIdx].cbd_datlen;
170
171 if (rtx.rxbd[rxIdx].cbd_sc & 0x003f) {
172 printf("fec: rx error %04x\n", rtx.rxbd[rxIdx].cbd_sc);
173 }
174 else {
175 /* Pass the packet up to the protocol layers. */
176 NetReceive(NetRxPackets[rxIdx], length - 4);
177 }
178
179
180 /* Give the buffer back to the FCC. */
181 rtx.rxbd[rxIdx].cbd_datlen = 0;
182
183 /* wrap around buffer index when necessary */
184 if ((rxIdx + 1) >= PKTBUFSRX) {
185 rtx.rxbd[PKTBUFSRX - 1].cbd_sc = (BD_ENET_RX_WRAP | BD_ENET_RX_EMPTY);
186 rxIdx = 0;
187 }
188 else {
189 rtx.rxbd[rxIdx].cbd_sc = BD_ENET_RX_EMPTY;
190 rxIdx++;
191 }
192 }
193 return length;
194}
195
196
197int eth_init(bd_t *bis)
198{
199 int i;
200 volatile immap_t *immr = (immap_t *)CFG_IMMR;
201 volatile cpm8260_t *cp = &(immr->im_cpm);
202 fcc_enet_t *pram_ptr;
203 unsigned long mem_addr;
204
205#if 0
206 mii_discover_phy();
207#endif
208
209 /* 28.9 - (1-2): ioports have been set up already */
210
211 /* 28.9 - (3): connect FCC's tx and rx clocks */
212 immr->im_cpmux.cmx_uar = 0;
213 immr->im_cpmux.cmx_fcr = (immr->im_cpmux.cmx_fcr & ~CFG_CMXFCR_MASK) |
214 CFG_CMXFCR_VALUE;
215
216 /* 28.9 - (4): GFMR: disable tx/rx, CCITT CRC, Mode Ethernet */
217 immr->im_fcc[CONFIG_ETHER_INDEX-1].fcc_gfmr =
218 FCC_GFMR_MODE_ENET | FCC_GFMR_TCRC_32;
219
220 /* 28.9 - (5): FPSMR: enable full duplex, select CCITT CRC for Ethernet */
221 immr->im_fcc[CONFIG_ETHER_INDEX-1].fcc_fpsmr = CFG_FCC_PSMR | FCC_PSMR_ENCRC;
222
223 /* 28.9 - (6): FDSR: Ethernet Syn */
224 immr->im_fcc[CONFIG_ETHER_INDEX-1].fcc_fdsr = 0xD555;
225
226 /* reset indeces to current rx/tx bd (see eth_send()/eth_rx()) */
227 rxIdx = 0;
228 txIdx = 0;
229
230 /* Setup Receiver Buffer Descriptors */
231 for (i = 0; i < PKTBUFSRX; i++)
232 {
233 rtx.rxbd[i].cbd_sc = BD_ENET_RX_EMPTY;
234 rtx.rxbd[i].cbd_datlen = 0;
235 rtx.rxbd[i].cbd_bufaddr = (uint)NetRxPackets[i];
236 }
237 rtx.rxbd[PKTBUFSRX - 1].cbd_sc |= BD_ENET_RX_WRAP;
238
239 /* Setup Ethernet Transmitter Buffer Descriptors */
240 for (i = 0; i < TX_BUF_CNT; i++)
241 {
242 rtx.txbd[i].cbd_sc = (BD_ENET_TX_PAD | BD_ENET_TX_LAST | BD_ENET_TX_TC);
243 rtx.txbd[i].cbd_datlen = 0;
244 rtx.txbd[i].cbd_bufaddr = (uint)&txbuf[i][0];
245 }
246 rtx.txbd[TX_BUF_CNT - 1].cbd_sc |= BD_ENET_TX_WRAP;
247
248 /* 28.9 - (7): initialise parameter ram */
249 pram_ptr = (fcc_enet_t *)&(immr->im_dprambase[PROFF_ENET]);
250
251 /* clear whole structure to make sure all reserved fields are zero */
252 memset((void*)pram_ptr, 0, sizeof(fcc_enet_t));
253
254 /*
255 * common Parameter RAM area
256 *
257 * Allocate space in the reserved FCC area of DPRAM for the
258 * internal buffers. No one uses this space (yet), so we
259 * can do this. Later, we will add resource management for
260 * this area.
261 */
262 mem_addr = CPM_FCC_SPECIAL_BASE + ((CONFIG_ETHER_INDEX-1) * 64);
263 pram_ptr->fen_genfcc.fcc_riptr = mem_addr;
264 pram_ptr->fen_genfcc.fcc_tiptr = mem_addr+32;
265 /*
266 * Set maximum bytes per receive buffer.
267 * It must be a multiple of 32.
268 */
269 pram_ptr->fen_genfcc.fcc_mrblr = PKT_MAXBLR_SIZE;
270 pram_ptr->fen_genfcc.fcc_rstate = (CPMFCR_GBL | CPMFCR_EB |
271 CFG_CPMFCR_RAMTYPE) << 24;
272 pram_ptr->fen_genfcc.fcc_rbase = (unsigned int)(&rtx.rxbd[rxIdx]);
273 pram_ptr->fen_genfcc.fcc_tstate = (CPMFCR_GBL | CPMFCR_EB |
274 CFG_CPMFCR_RAMTYPE) << 24;
275 pram_ptr->fen_genfcc.fcc_tbase = (unsigned int)(&rtx.txbd[txIdx]);
276
277 /* protocol-specific area */
278 pram_ptr->fen_cmask = 0xdebb20e3; /* CRC mask */
279 pram_ptr->fen_cpres = 0xffffffff; /* CRC preset */
280 pram_ptr->fen_retlim = 15; /* Retry limit threshold */
281 pram_ptr->fen_mflr = PKT_MAXBUF_SIZE; /* maximum frame length register */
282 /*
283 * Set Ethernet station address.
284 *
285 * This is supplied in the board information structure, so we
286 * copy that into the controller.
287 * So, far we have only been given one Ethernet address. We make
288 * it unique by setting a few bits in the upper byte of the
289 * non-static part of the address.
290 */
291#define ea bis->bi_enetaddr
292 pram_ptr->fen_paddrh = (ea[5] << 8) + ea[4];
293 pram_ptr->fen_paddrm = (ea[3] << 8) + ea[2];
294 pram_ptr->fen_paddrl = (ea[1] << 8) + ea[0];
295#undef ea
296 pram_ptr->fen_minflr = PKT_MINBUF_SIZE; /* minimum frame length register */
297 /* pad pointer. use tiptr since we don't need a specific padding char */
298 pram_ptr->fen_padptr = pram_ptr->fen_genfcc.fcc_tiptr;
299 pram_ptr->fen_maxd1 = PKT_MAXDMA_SIZE; /* maximum DMA1 length */
300 pram_ptr->fen_maxd2 = PKT_MAXDMA_SIZE; /* maximum DMA2 length */
301 pram_ptr->fen_rfthr = 1;
302 pram_ptr->fen_rfcnt = 1;
303#if 0
304 printf("pram_ptr->fen_genfcc.fcc_rbase %08lx\n",
305 pram_ptr->fen_genfcc.fcc_rbase);
306 printf("pram_ptr->fen_genfcc.fcc_tbase %08lx\n",
307 pram_ptr->fen_genfcc.fcc_tbase);
308#endif
309
310 /* 28.9 - (8): clear out events in FCCE */
311 immr->im_fcc[CONFIG_ETHER_INDEX-1].fcc_fcce = ~0x0;
312
313 /* 28.9 - (9): FCCM: mask all events */
314 immr->im_fcc[CONFIG_ETHER_INDEX-1].fcc_fccm = 0;
315
316 /* 28.9 - (10-12): we don't use ethernet interrupts */
317
318 /* 28.9 - (13)
319 *
320 * Let's re-initialize the channel now. We have to do it later
321 * than the manual describes because we have just now finished
322 * the BD initialization.
323 */
324 cp->cp_cpcr = mk_cr_cmd(CPM_CR_ENET_PAGE,
325 CPM_CR_ENET_SBLOCK,
326 0x0c,
327 CPM_CR_INIT_TRX) | CPM_CR_FLG;
328 do {
329 __asm__ __volatile__ ("eieio");
330 } while (cp->cp_cpcr & CPM_CR_FLG);
331
332 /* 28.9 - (14): enable tx/rx in gfmr */
333 immr->im_fcc[CONFIG_ETHER_INDEX-1].fcc_gfmr |= FCC_GFMR_ENT | FCC_GFMR_ENR;
334
335 return 1;
336}
337
338void eth_halt(void)
339{
340 volatile immap_t *immr = (immap_t *)CFG_IMMR;
341
342 /* write GFMR: disable tx/rx */
343 immr->im_fcc[CONFIG_ETHER_INDEX-1].fcc_gfmr &=
344 ~(FCC_GFMR_ENT | FCC_GFMR_ENR);
345}
346
347#endif /* CONFIG_ETHER_ON_FCC && CFG_CMD_NET */