blob: bd2fcc927f5f77d7255cb4318ba6bb91403b57c6 [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>
wdenkaacf9a42003-01-17 16:27:01 +000043#include <malloc.h>
wdenkaffae2b2002-08-17 09:36:01 +000044#include <asm/cpm_8260.h>
45#include <mpc8260.h>
wdenkaffae2b2002-08-17 09:36:01 +000046#include <command.h>
47#include <config.h>
wdenkaacf9a42003-01-17 16:27:01 +000048#include <net.h>
wdenkaffae2b2002-08-17 09:36:01 +000049
wdenkaacf9a42003-01-17 16:27:01 +000050#if defined(CONFIG_ETHER_ON_FCC) && (CONFIG_COMMANDS & CFG_CMD_NET) && \
51 defined(CONFIG_NET_MULTI)
wdenkaffae2b2002-08-17 09:36:01 +000052
wdenkaacf9a42003-01-17 16:27:01 +000053static struct ether_fcc_info_s
54{
55 int ether_index;
56 int proff_enet;
57 ulong cpm_cr_enet_sblock;
58 ulong cpm_cr_enet_page;
59 ulong cmxfcr_mask;
60 ulong cmxfcr_value;
61}
62 ether_fcc_info[] =
63{
64#ifdef CONFIG_ETHER_ON_FCC1
65{
66 0,
67 PROFF_FCC1,
68 CPM_CR_FCC1_SBLOCK,
69 CPM_CR_FCC1_PAGE,
70 CFG_CMXFCR_MASK1,
71 CFG_CMXFCR_VALUE1
72},
wdenkaffae2b2002-08-17 09:36:01 +000073#endif
wdenkaacf9a42003-01-17 16:27:01 +000074
75#ifdef CONFIG_ETHER_ON_FCC2
76{
77 1,
78 PROFF_FCC2,
79 CPM_CR_FCC2_SBLOCK,
80 CPM_CR_FCC2_PAGE,
81 CFG_CMXFCR_MASK2,
82 CFG_CMXFCR_VALUE2
83},
84#endif
85
86#ifdef CONFIG_ETHER_ON_FCC3
87{
88 2,
89 PROFF_FCC3,
90 CPM_CR_FCC3_SBLOCK,
91 CPM_CR_FCC3_PAGE,
92 CFG_CMXFCR_MASK3,
93 CFG_CMXFCR_VALUE3
94},
95#endif
96};
97
wdenkaffae2b2002-08-17 09:36:01 +000098/*---------------------------------------------------------------------*/
99
100/* Maximum input DMA size. Must be a should(?) be a multiple of 4. */
101#define PKT_MAXDMA_SIZE 1520
102
103/* The FCC stores dest/src/type, data, and checksum for receive packets. */
104#define PKT_MAXBUF_SIZE 1518
105#define PKT_MINBUF_SIZE 64
106
107/* Maximum input buffer size. Must be a multiple of 32. */
108#define PKT_MAXBLR_SIZE 1536
109
110#define TOUT_LOOP 1000000
111
112#define TX_BUF_CNT 2
113#ifdef __GNUC__
114static char txbuf[TX_BUF_CNT][PKT_MAXBLR_SIZE] __attribute__ ((aligned(8)));
115#else
116#error "txbuf must be 64-bit aligned"
117#endif
118
119static uint rxIdx; /* index of the current RX buffer */
120static uint txIdx; /* index of the current TX buffer */
121
122/*
123 * FCC Ethernet Tx and Rx buffer descriptors.
124 * Provide for Double Buffering
125 * Note: PKTBUFSRX is defined in net.h
126 */
127
128typedef volatile struct rtxbd {
129 cbd_t rxbd[PKTBUFSRX];
130 cbd_t txbd[TX_BUF_CNT];
131} RTXBD;
132
133/* Good news: the FCC supports external BDs! */
134#ifdef __GNUC__
135static RTXBD rtx __attribute__ ((aligned(8)));
136#else
137#error "rtx must be 64-bit aligned"
138#endif
139
wdenkaacf9a42003-01-17 16:27:01 +0000140static int fec_send(struct eth_device* dev, volatile void *packet, int length)
wdenkaffae2b2002-08-17 09:36:01 +0000141{
142 int i;
143 int result = 0;
144
145 if (length <= 0) {
146 printf("fec: bad packet size: %d\n", length);
147 goto out;
148 }
149
150 for(i=0; rtx.txbd[txIdx].cbd_sc & BD_ENET_TX_READY; i++) {
151 if (i >= TOUT_LOOP) {
152 printf("fec: tx buffer not ready\n");
153 goto out;
154 }
155 }
156
157 rtx.txbd[txIdx].cbd_bufaddr = (uint)packet;
158 rtx.txbd[txIdx].cbd_datlen = length;
159 rtx.txbd[txIdx].cbd_sc |= (BD_ENET_TX_READY | BD_ENET_TX_LAST |
160 BD_ENET_TX_WRAP);
161
162 for(i=0; rtx.txbd[txIdx].cbd_sc & BD_ENET_TX_READY; i++) {
163 if (i >= TOUT_LOOP) {
164 printf("fec: tx error\n");
165 goto out;
166 }
167 }
168
169#ifdef ET_DEBUG
170 printf("cycles: %d status: %04x\n", i, rtx.txbd[txIdx].cbd_sc);
171#endif
172
173 /* return only status bits */
174 result = rtx.txbd[txIdx].cbd_sc & BD_ENET_TX_STATS;
175
176out:
177 return result;
178}
179
wdenkaacf9a42003-01-17 16:27:01 +0000180static int fec_recv(struct eth_device* dev)
wdenkaffae2b2002-08-17 09:36:01 +0000181{
182 int length;
183
184 for (;;)
185 {
186 if (rtx.rxbd[rxIdx].cbd_sc & BD_ENET_RX_EMPTY) {
187 length = -1;
188 break; /* nothing received - leave for() loop */
189 }
190 length = rtx.rxbd[rxIdx].cbd_datlen;
191
192 if (rtx.rxbd[rxIdx].cbd_sc & 0x003f) {
193 printf("fec: rx error %04x\n", rtx.rxbd[rxIdx].cbd_sc);
194 }
195 else {
196 /* Pass the packet up to the protocol layers. */
197 NetReceive(NetRxPackets[rxIdx], length - 4);
198 }
199
200
201 /* Give the buffer back to the FCC. */
202 rtx.rxbd[rxIdx].cbd_datlen = 0;
203
204 /* wrap around buffer index when necessary */
205 if ((rxIdx + 1) >= PKTBUFSRX) {
206 rtx.rxbd[PKTBUFSRX - 1].cbd_sc = (BD_ENET_RX_WRAP | BD_ENET_RX_EMPTY);
207 rxIdx = 0;
208 }
209 else {
210 rtx.rxbd[rxIdx].cbd_sc = BD_ENET_RX_EMPTY;
211 rxIdx++;
212 }
213 }
214 return length;
215}
216
217
wdenkaacf9a42003-01-17 16:27:01 +0000218static int fec_init(struct eth_device* dev, bd_t *bis)
wdenkaffae2b2002-08-17 09:36:01 +0000219{
wdenkaacf9a42003-01-17 16:27:01 +0000220 struct ether_fcc_info_s * info = dev->priv;
wdenkaffae2b2002-08-17 09:36:01 +0000221 int i;
222 volatile immap_t *immr = (immap_t *)CFG_IMMR;
223 volatile cpm8260_t *cp = &(immr->im_cpm);
224 fcc_enet_t *pram_ptr;
225 unsigned long mem_addr;
226
227#if 0
228 mii_discover_phy();
229#endif
230
231 /* 28.9 - (1-2): ioports have been set up already */
232
233 /* 28.9 - (3): connect FCC's tx and rx clocks */
234 immr->im_cpmux.cmx_uar = 0;
wdenkaacf9a42003-01-17 16:27:01 +0000235 immr->im_cpmux.cmx_fcr = (immr->im_cpmux.cmx_fcr & ~info->cmxfcr_mask) |
236 info->cmxfcr_value;
wdenkaffae2b2002-08-17 09:36:01 +0000237
238 /* 28.9 - (4): GFMR: disable tx/rx, CCITT CRC, Mode Ethernet */
wdenkaacf9a42003-01-17 16:27:01 +0000239 immr->im_fcc[info->ether_index].fcc_gfmr =
wdenkaffae2b2002-08-17 09:36:01 +0000240 FCC_GFMR_MODE_ENET | FCC_GFMR_TCRC_32;
241
242 /* 28.9 - (5): FPSMR: enable full duplex, select CCITT CRC for Ethernet */
wdenkaacf9a42003-01-17 16:27:01 +0000243 immr->im_fcc[info->ether_index].fcc_fpsmr = CFG_FCC_PSMR | FCC_PSMR_ENCRC;
wdenkaffae2b2002-08-17 09:36:01 +0000244
245 /* 28.9 - (6): FDSR: Ethernet Syn */
wdenkaacf9a42003-01-17 16:27:01 +0000246 immr->im_fcc[info->ether_index].fcc_fdsr = 0xD555;
wdenkaffae2b2002-08-17 09:36:01 +0000247
248 /* reset indeces to current rx/tx bd (see eth_send()/eth_rx()) */
249 rxIdx = 0;
250 txIdx = 0;
251
252 /* Setup Receiver Buffer Descriptors */
253 for (i = 0; i < PKTBUFSRX; i++)
254 {
255 rtx.rxbd[i].cbd_sc = BD_ENET_RX_EMPTY;
256 rtx.rxbd[i].cbd_datlen = 0;
257 rtx.rxbd[i].cbd_bufaddr = (uint)NetRxPackets[i];
258 }
259 rtx.rxbd[PKTBUFSRX - 1].cbd_sc |= BD_ENET_RX_WRAP;
260
261 /* Setup Ethernet Transmitter Buffer Descriptors */
262 for (i = 0; i < TX_BUF_CNT; i++)
263 {
264 rtx.txbd[i].cbd_sc = (BD_ENET_TX_PAD | BD_ENET_TX_LAST | BD_ENET_TX_TC);
265 rtx.txbd[i].cbd_datlen = 0;
266 rtx.txbd[i].cbd_bufaddr = (uint)&txbuf[i][0];
267 }
268 rtx.txbd[TX_BUF_CNT - 1].cbd_sc |= BD_ENET_TX_WRAP;
269
270 /* 28.9 - (7): initialise parameter ram */
wdenkaacf9a42003-01-17 16:27:01 +0000271 pram_ptr = (fcc_enet_t *)&(immr->im_dprambase[info->proff_enet]);
wdenkaffae2b2002-08-17 09:36:01 +0000272
273 /* clear whole structure to make sure all reserved fields are zero */
274 memset((void*)pram_ptr, 0, sizeof(fcc_enet_t));
275
276 /*
277 * common Parameter RAM area
278 *
279 * Allocate space in the reserved FCC area of DPRAM for the
280 * internal buffers. No one uses this space (yet), so we
281 * can do this. Later, we will add resource management for
282 * this area.
283 */
wdenkaacf9a42003-01-17 16:27:01 +0000284 mem_addr = CPM_FCC_SPECIAL_BASE + ((info->ether_index) * 64);
wdenkaffae2b2002-08-17 09:36:01 +0000285 pram_ptr->fen_genfcc.fcc_riptr = mem_addr;
286 pram_ptr->fen_genfcc.fcc_tiptr = mem_addr+32;
287 /*
288 * Set maximum bytes per receive buffer.
289 * It must be a multiple of 32.
290 */
291 pram_ptr->fen_genfcc.fcc_mrblr = PKT_MAXBLR_SIZE;
292 pram_ptr->fen_genfcc.fcc_rstate = (CPMFCR_GBL | CPMFCR_EB |
293 CFG_CPMFCR_RAMTYPE) << 24;
294 pram_ptr->fen_genfcc.fcc_rbase = (unsigned int)(&rtx.rxbd[rxIdx]);
295 pram_ptr->fen_genfcc.fcc_tstate = (CPMFCR_GBL | CPMFCR_EB |
296 CFG_CPMFCR_RAMTYPE) << 24;
297 pram_ptr->fen_genfcc.fcc_tbase = (unsigned int)(&rtx.txbd[txIdx]);
298
299 /* protocol-specific area */
300 pram_ptr->fen_cmask = 0xdebb20e3; /* CRC mask */
301 pram_ptr->fen_cpres = 0xffffffff; /* CRC preset */
302 pram_ptr->fen_retlim = 15; /* Retry limit threshold */
303 pram_ptr->fen_mflr = PKT_MAXBUF_SIZE; /* maximum frame length register */
304 /*
305 * Set Ethernet station address.
306 *
307 * This is supplied in the board information structure, so we
308 * copy that into the controller.
309 * So, far we have only been given one Ethernet address. We make
310 * it unique by setting a few bits in the upper byte of the
311 * non-static part of the address.
312 */
wdenkaacf9a42003-01-17 16:27:01 +0000313#define ea eth_get_dev()->enetaddr
wdenkaffae2b2002-08-17 09:36:01 +0000314 pram_ptr->fen_paddrh = (ea[5] << 8) + ea[4];
315 pram_ptr->fen_paddrm = (ea[3] << 8) + ea[2];
316 pram_ptr->fen_paddrl = (ea[1] << 8) + ea[0];
317#undef ea
318 pram_ptr->fen_minflr = PKT_MINBUF_SIZE; /* minimum frame length register */
319 /* pad pointer. use tiptr since we don't need a specific padding char */
320 pram_ptr->fen_padptr = pram_ptr->fen_genfcc.fcc_tiptr;
321 pram_ptr->fen_maxd1 = PKT_MAXDMA_SIZE; /* maximum DMA1 length */
322 pram_ptr->fen_maxd2 = PKT_MAXDMA_SIZE; /* maximum DMA2 length */
323 pram_ptr->fen_rfthr = 1;
324 pram_ptr->fen_rfcnt = 1;
325#if 0
326 printf("pram_ptr->fen_genfcc.fcc_rbase %08lx\n",
327 pram_ptr->fen_genfcc.fcc_rbase);
328 printf("pram_ptr->fen_genfcc.fcc_tbase %08lx\n",
329 pram_ptr->fen_genfcc.fcc_tbase);
330#endif
331
332 /* 28.9 - (8): clear out events in FCCE */
wdenkaacf9a42003-01-17 16:27:01 +0000333 immr->im_fcc[info->ether_index].fcc_fcce = ~0x0;
wdenkaffae2b2002-08-17 09:36:01 +0000334
335 /* 28.9 - (9): FCCM: mask all events */
wdenkaacf9a42003-01-17 16:27:01 +0000336 immr->im_fcc[info->ether_index].fcc_fccm = 0;
wdenkaffae2b2002-08-17 09:36:01 +0000337
338 /* 28.9 - (10-12): we don't use ethernet interrupts */
339
340 /* 28.9 - (13)
341 *
342 * Let's re-initialize the channel now. We have to do it later
343 * than the manual describes because we have just now finished
344 * the BD initialization.
345 */
wdenkaacf9a42003-01-17 16:27:01 +0000346 cp->cp_cpcr = mk_cr_cmd(info->cpm_cr_enet_page,
347 info->cpm_cr_enet_sblock,
wdenkaffae2b2002-08-17 09:36:01 +0000348 0x0c,
349 CPM_CR_INIT_TRX) | CPM_CR_FLG;
350 do {
351 __asm__ __volatile__ ("eieio");
352 } while (cp->cp_cpcr & CPM_CR_FLG);
353
354 /* 28.9 - (14): enable tx/rx in gfmr */
wdenkaacf9a42003-01-17 16:27:01 +0000355 immr->im_fcc[info->ether_index].fcc_gfmr |= FCC_GFMR_ENT | FCC_GFMR_ENR;
wdenkaffae2b2002-08-17 09:36:01 +0000356
357 return 1;
358}
359
wdenkaacf9a42003-01-17 16:27:01 +0000360static void fec_halt(struct eth_device* dev)
wdenkaffae2b2002-08-17 09:36:01 +0000361{
wdenkaacf9a42003-01-17 16:27:01 +0000362 struct ether_fcc_info_s * info = dev->priv;
wdenkaffae2b2002-08-17 09:36:01 +0000363 volatile immap_t *immr = (immap_t *)CFG_IMMR;
364
365 /* write GFMR: disable tx/rx */
wdenkaacf9a42003-01-17 16:27:01 +0000366 immr->im_fcc[info->ether_index].fcc_gfmr &=
wdenkaffae2b2002-08-17 09:36:01 +0000367 ~(FCC_GFMR_ENT | FCC_GFMR_ENR);
368}
369
wdenkaacf9a42003-01-17 16:27:01 +0000370int fec_initialize(bd_t *bis)
371{
372 struct eth_device* dev;
373 int i;
374
375 for (i = 0; i < sizeof(ether_fcc_info) / sizeof(ether_fcc_info[0]); i++)
376 {
377 dev = (struct eth_device*) malloc(sizeof *dev);
378 memset(dev, 0, sizeof *dev);
379
380 sprintf(dev->name, "FCC%d ETHERNET",
381 ether_fcc_info[i].ether_index + 1);
382 dev->priv = &ether_fcc_info[i];
383 dev->init = fec_init;
384 dev->halt = fec_halt;
385 dev->send = fec_send;
386 dev->recv = fec_recv;
387
388 eth_register(dev);
389 }
390
391 return 1;
392}
393
394#endif /* CONFIG_ETHER_ON_FCC && CFG_CMD_NET && CONFIG_NET_MULTI */