blob: 34f04f56263df8d31e1b19777e07a21cb0ed4ec4 [file] [log] [blame]
Gary Jennejohnd38bfdd2008-11-09 12:45:03 +01001/*
2 * (C) Copyright 2008
3 * Gary Jennejohn, DENX Software Engineering GmbH, garyj@denx.de.
4 *
5 * Based in part on cpu/mpc8260/ether_scc.c.
6 *
7 * See file CREDITS for list of people who contributed to this
8 * project.
9 *
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License as
12 * published by the Free Software Foundation; either version 2 of
13 * the License, or (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
23 * MA 02111-1307 USA
24 */
25
26#include <common.h>
27#include <malloc.h>
28#include <net.h>
29
30#ifdef CONFIG_KEYMILE_HDLC_ENET
31
32#include "../common/keymile_hdlc_enet.h"
33
34char keymile_slot; /* our slot number in the backplane */
35
36/*
37 * Since, except during initialization, ethact is always HDLC ETHERNET
38 * while we're in the driver, just use serial_printf() everywhere for
39 * output. This avoids possible conflicts when netconsole is being
40 * used.
41 */
42#define dprintf(fmt, args...) serial_printf(fmt, ##args)
43
44static int already_inited;
45
46/*
47 * SCC Ethernet Tx and Rx buffer descriptors allocated at the
48 * immr->udata_bd address on Dual-Port RAM
49 * Provide for Double Buffering
50 */
51typedef volatile struct CommonBufferDescriptor {
52 cbd_t txbd; /* Tx BD */
53 cbd_t rxbd[HDLC_PKTBUFSRX]; /* Rx BD */
54} RTXBD;
55
56static RTXBD *rtx;
57
58int keymile_hdlc_enet_init(struct eth_device *, bd_t *);
59void keymile_hdlc_enet_halt(struct eth_device *);
60extern void keymile_hdlc_enet_init_bds(RTXBD *);
61extern void initCachedNumbers(int);
62
63/* Use SCC1 */
64#define CPM_CR_SCC_PAGE CPM_CR_SCC1_PAGE
65#define CPM_CR_SCC_SBLOCK CPM_CR_SCC1_SBLOCK
66#define CMXSCR_MASK (CMXSCR_GR1|CMXSCR_SC1|\
67 CMXSCR_RS1CS_MSK|CMXSCR_TS1CS_MSK)
68#define CMXSCR_VALUE (CMXSCR_RS1CS_CLK11|CMXSCR_TS1CS_CLK11)
69#define MGC_PROFF_HDLC PROFF_SCC1
70#define MGC_SCC_HDLC 0 /* Index, not number! */
71
72int keymile_hdlc_enet_init(struct eth_device *dev, bd_t *bis)
73{
74 /* int i; */
75 uint dpr;
76 /* volatile cbd_t *bdp; */
77 volatile immap_t *im = (immap_t *)CONFIG_SYS_IMMR;
78 volatile cpm8260_t *cp = &(im->im_cpm);
79 volatile scc_t *sccp;
80 volatile scc_hdlc_t *hpr;
81 volatile iop8260_t *iop;
82
83 if (already_inited)
84 return 0;
85
86 hpr = (scc_hdlc_t *)(&im->im_dprambase[MGC_PROFF_HDLC]);
87 sccp = (scc_t *)(&im->im_scc[MGC_SCC_HDLC]);
88 iop = &im->im_ioport;
89
90 /*
91 * Disable receive and transmit just in case.
92 */
93 sccp->scc_gsmrl &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
94
95 /*
96 * Avoid exhausting DPRAM, which would cause a panic.
97 */
98 if (rtx == NULL) {
99 /* dpr is an offset into dpram */
100 dpr = m8260_cpm_dpalloc(sizeof(RTXBD), 8);
101 rtx = (RTXBD *)&im->im_dprambase[dpr];
102 }
103
104 /* We need the slot number for addressing. */
105 keymile_slot = *(char *)(CONFIG_SYS_SLOT_ID_BASE +
106 CONFIG_SYS_SLOT_ID_OFF) & CONFIG_SYS_SLOT_ID_MASK;
107 /*
108 * Be consistent with the Linux driver and set
109 * only enetaddr[0].
110 *
111 * Always add 1 to the slot number so that
112 * there are no problems with an ethaddr which
113 * is all 0s. This should be acceptable because
114 * a board should never have a slot number of 255,
115 * which is the broadcast address. The HDLC addressing
116 * uses only the slot number.
117 */
118 dev->enetaddr[0] = keymile_slot + 1;
119#ifdef TEST_IT
120 dprintf("slot %d\n", keymile_slot);
121#endif
122
123 /* use pd30, pd31 pins for TXD1, RXD1 respectively */
124 iop->iop_ppard |= (0x80000000 >> 30) | (0x80000000 >> 31);
125 iop->iop_pdird |= (0x80000000 >> 30);
126 iop->iop_psord |= (0x80000000 >> 30);
127
128 /* use pc21 as CLK11 */
129 iop->iop_pparc |= (0x80000000 >> 21);
130 iop->iop_pdirc &= ~(0x80000000 >> 21);
131 iop->iop_psorc &= ~(0x80000000 >> 21);
132
133 /* use pc15 as CTS1 */
134 iop->iop_pparc |= (0x80000000 >> 15);
135 iop->iop_pdirc &= ~(0x80000000 >> 15);
136 iop->iop_psorc &= ~(0x80000000 >> 15);
137
138 /*
139 * SI clock routing
140 * use CLK11
141 * this also connects SCC1 to NMSI
142 */
143 im->im_cpmux.cmx_scr = (im->im_cpmux.cmx_scr & ~CMXSCR_MASK) |
144 CMXSCR_VALUE;
145
146 /* keymile_rxIdx = 0; */
147
148 /*
149 * Initialize function code registers for big-endian.
150 */
151 hpr->sh_genscc.scc_rfcr = CPMFCR_EB;
152 hpr->sh_genscc.scc_tfcr = CPMFCR_EB;
153
154 /*
155 * Set maximum bytes per receive buffer.
156 */
157 hpr->sh_genscc.scc_mrblr = MAX_FRAME_LENGTH;
158
159 /* Setup CRC generator values for HDLC */
160 hpr->sh_cmask = 0x0000F0B8;
161 hpr->sh_cpres = 0x0000FFFF;
162
163 /* Initialize all error counters to 0 */
164 hpr->sh_disfc = 0;
165 hpr->sh_crcec = 0;
166 hpr->sh_abtsc = 0;
167 hpr->sh_nmarc = 0;
168 hpr->sh_retrc = 0;
169
170 /* Set maximum frame length size */
171 hpr->sh_mflr = MAX_FRAME_LENGTH;
172
173 /* set to 1 for per frame processing change later if needed */
174 hpr->sh_rfthr = 1;
175
176 hpr->sh_hmask = 0xff;
177
178 hpr->sh_haddr2 = SET_HDLC_UUA(keymile_slot);
179 hpr->sh_haddr3 = hpr->sh_haddr2;
180 hpr->sh_haddr4 = hpr->sh_haddr2;
181 /* broadcast */
182 hpr->sh_haddr1 = HDLC_BCAST;
183
184 hpr->sh_genscc.scc_rbase = (unsigned int) &rtx->rxbd[0];
185 hpr->sh_genscc.scc_tbase = (unsigned int) &rtx->txbd;
186
187#if 0
188 /*
189 * Initialize the buffer descriptors.
190 */
191 bdp = &rtx->txbd;
192 bdp->cbd_sc = 0;
193 bdp->cbd_bufaddr = 0;
194 bdp->cbd_sc = BD_SC_WRAP;
195
196 /*
197 * Setup RX packet buffers, aligned correctly.
198 * Borrowed from net/net.c.
199 */
200 MyRxPackets[0] = &MyPktBuf[0] + (PKTALIGN - 1);
201 MyRxPackets[0] -= (ulong)MyRxPackets[0] % PKTALIGN;
202 for (i = 1; i < HDLC_PKTBUFSRX; i++)
203 MyRxPackets[i] = MyRxPackets[0] + i * PKT_MAXBLR_SIZE;
204
205 bdp = &rtx->rxbd[0];
206 for (i = 0; i < HDLC_PKTBUFSRX; i++) {
207 bdp->cbd_sc = BD_SC_EMPTY;
208 /* Leave space at the start for INET header. */
209 bdp->cbd_bufaddr = (unsigned int)(MyRxPackets[i] +
210 INET_HDR_ALIGN);
211 bdp++;
212 }
213 bdp--;
214 bdp->cbd_sc |= BD_SC_WRAP;
215#else
216 keymile_hdlc_enet_init_bds(rtx);
217#endif
218
219 /* Let's re-initialize the channel now. We have to do it later
220 * than the manual describes because we have just now finished
221 * the BD initialization.
222 */
223 cp->cp_cpcr = mk_cr_cmd(CPM_CR_SCC_PAGE, CPM_CR_SCC_SBLOCK,
224 0, CPM_CR_INIT_TRX) | CPM_CR_FLG;
225 while (cp->cp_cpcr & CPM_CR_FLG);
226
227 sccp->scc_gsmrl = SCC_GSMRL_MODE_HDLC;
228 /* CTSS=1 */
229 sccp->scc_gsmrh = SCC_GSMRH_CTSS;
230 /* NOF=0, RTE=1, DRT=0, BUS=1 */
231 sccp->scc_psmr = ((0x8000 >> 6) | (0x8000 >> 10));
232
233/* loopback for local testing */
234#ifdef GJTEST
235 dprintf("LOOPBACK!\n");
236 sccp->scc_gsmrl |= SCC_GSMRL_DIAG_LOOP;
237#endif
238
239 /*
240 * Disable all interrupts and clear all pending
241 * events.
242 */
243 sccp->scc_sccm = 0;
244 sccp->scc_scce = 0xffff;
245
246 /*
247 * And last, enable the transmit and receive processing.
248 */
249 sccp->scc_gsmrl |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT);
250
251 dprintf("%s: HDLC ENET Version 0.3 on SCC%d\n", dev->name,
252 MGC_SCC_HDLC + 1);
253
254 /*
255 * We may not get an ARP packet because ARP was already done on
256 * a different interface, so initialize the cached values now.
257 */
258 initCachedNumbers(1);
259
260 already_inited = 1;
261
262 return 0;
263}
264
265void keymile_hdlc_enet_halt(struct eth_device *dev)
266{
267#if 0 /* just return, but keep this for reference */
268 volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
269
270 /* maybe should do a graceful stop here? */
271 immr->im_scc[MGC_SCC_HDLC].scc_gsmrl &=
272 ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
273#endif
274}
275
276#endif /* CONFIG_MGCOGE_HDLC_ENET */