]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - board/keymile/mgcoge/mgcoge_hdlc_enet.c
Merge branch 'master' of git://git.denx.de/u-boot-ppc4xx
[karo-tx-uboot.git] / board / keymile / mgcoge / mgcoge_hdlc_enet.c
1 /*
2  * (C) Copyright 2008
3  * Gary Jennejohn, DENX Software Engineering GmbH, garyj@denx.de.
4  *
5  * Based in part on arch/powerpc/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
34 char 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
44 static 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   */
51 typedef volatile struct CommonBufferDescriptor {
52     cbd_t txbd;                 /* Tx BD */
53     cbd_t rxbd[HDLC_PKTBUFSRX]; /* Rx BD */
54 } RTXBD;
55
56 static RTXBD *rtx;
57
58 int keymile_hdlc_enet_init(struct eth_device *, bd_t *);
59 void keymile_hdlc_enet_halt(struct eth_device *);
60 extern void keymile_hdlc_enet_init_bds(RTXBD *);
61 extern 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
72 int 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
265 void 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 */