]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - board/keymile/km8xx/km8xx_hdlc_enet.c
Merge branch 'master' of git://git.denx.de/u-boot-ppc4xx
[karo-tx-uboot.git] / board / keymile / km8xx / km8xx_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/mpc8xx/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>     /* commproc.h is included here */
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 SCC4 */
64 #define MGS_CPM_CR_HDLC CPM_CR_CH_SCC4
65 #define MGS_PROFF_HDLC  PROFF_SCC4
66 #define MGS_SCC_HDLC    3       /* Index, not number! */
67
68 int keymile_hdlc_enet_init(struct eth_device *dev, bd_t *bis)
69 {
70         /* int i; */
71         /* volatile cbd_t *bdp; */
72         volatile cpm8xx_t *cp;
73         volatile scc_t *sccp;
74         volatile hdlc_pram_t *hpr;
75         volatile iop8xx_t *iop;
76
77         if (already_inited)
78                 return 0;
79
80         cp = (cpm8xx_t *)&(((volatile immap_t *)CONFIG_SYS_IMMR)->im_cpm);
81         hpr = (hdlc_pram_t *)(&cp->cp_dparam[MGS_PROFF_HDLC]);
82         sccp = (volatile scc_t *)(&cp->cp_scc[MGS_SCC_HDLC]);
83         iop = (iop8xx_t *)&(((volatile immap_t *)CONFIG_SYS_IMMR)->im_ioport);
84
85         /*
86          * Disable receive and transmit just in case.
87          */
88         sccp->scc_gsmrl &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
89
90 #ifndef CONFIG_SYS_ALLOC_DPRAM
91 #error "CONFIG_SYS_ALLOC_DPRAM must be defined"
92 #else
93         /*
94          * Avoid exhausting DPRAM, which would cause a panic.
95          * Actually this isn't really necessary, but leave it here
96          * for safety's sake.
97          */
98         if (rtx == NULL) {
99                 rtx = (RTXBD *) (cp->cp_dpmem +
100                          dpram_alloc_align(sizeof(RTXBD), 8));
101                 if (rtx == (RTXBD *)CPM_DP_NOSPACE)
102                         return -1;
103                 memset((void *)rtx, 0, sizeof(RTXBD));
104         }
105 #endif /* !CONFIG_SYS_ALLOC_DPRAM */
106
107         /* We need the slot number for addressing. */
108         keymile_slot = *(char *)(CONFIG_SYS_SLOT_ID_BASE +
109                 CONFIG_SYS_SLOT_ID_OFF) & CONFIG_SYS_SLOT_ID_MASK;
110         /*
111          * Be consistent with the Linux driver and set
112          * only enetaddr[0].
113          *
114          * Always add 1 to the slot number so that
115          * there are no problems with an ethaddr which
116          * is all 0s.  This should be acceptable because
117          * a board should never have a slot number of 255,
118          * which is the broadcast address.  The HDLC addressing
119          * uses only the slot number.
120          */
121         dev->enetaddr[0] = keymile_slot + 1;
122
123 #ifdef TEST_IT
124         dprintf("slot %d\n", keymile_slot);
125 #endif
126
127         /* use pa8, pa9 pins for TXD4, RXD4 respectively */
128         iop->iop_papar |= ((0x8000 >> 8) | (0x8000 >> 9));
129         iop->iop_padir &= ~((0x8000 >> 8) | (0x8000 >> 9));
130         iop->iop_paodr &= ~((0x8000 >> 8) | (0x8000 >> 9));
131
132         /* also use pa0 as CLK8 */
133         iop->iop_papar |= 0x8000;
134         iop->iop_padir &= ~0x8000;
135         iop->iop_paodr &= ~0x8000;
136
137         /* use pc5 as CTS4 */
138         iop->iop_pcpar &= ~(0x8000 >> 5);
139         iop->iop_pcdir &= ~(0x8000 >> 5);
140         iop->iop_pcso  |= (0x8000 >> 5);
141
142         /*
143          * SI clock routing
144          * use CLK8
145          * this also connects SCC4 to NMSI
146          */
147         cp->cp_sicr = (cp->cp_sicr & ~0xff000000) | 0x3f000000;
148
149         /* keymile_rxIdx = 0; */
150
151         /*
152          * Initialize function code registers for big-endian.
153          */
154         hpr->rfcr = SCC_EB;
155         hpr->tfcr = SCC_EB;
156
157         /*
158          * Set maximum bytes per receive buffer.
159          */
160         hpr->mrblr = MAX_FRAME_LENGTH;
161
162         /* Setup CRC generator values for HDLC */
163         hpr->c_mask = 0x0000F0B8;
164         hpr->c_pres = 0x0000FFFF;
165
166         /* Initialize all error counters to 0 */
167         hpr->disfc = 0;
168         hpr->crcec = 0;
169         hpr->abtsc = 0;
170         hpr->nmarc = 0;
171         hpr->retrc = 0;
172
173         /* Set maximum frame length size */
174         hpr->mflr = MAX_FRAME_LENGTH;
175
176         /* set to 1 for per frame processing change later if needed */
177         hpr->rfthr = 1;
178
179         hpr->hmask = 0xff;
180
181         hpr->haddr2 = SET_HDLC_UUA(keymile_slot);
182         hpr->haddr3 = hpr->haddr2;
183         hpr->haddr4 = hpr->haddr2;
184         /* broadcast */
185         hpr->haddr1 = HDLC_BCAST;
186
187         hpr->rbase = (unsigned int) &rtx->rxbd[0];
188         hpr->tbase = (unsigned int) &rtx->txbd;
189
190 #if 0
191         /*
192          * Initialize the buffer descriptors.
193          */
194         bdp = &rtx->txbd;
195         bdp->cbd_sc = 0;
196         bdp->cbd_bufaddr = 0;
197         bdp->cbd_sc = BD_SC_WRAP;
198
199         /*
200          *      Setup RX packet buffers, aligned correctly.
201          *      Borrowed from net/net.c.
202          */
203         MyRxPackets[0] = &MyPktBuf[0] + (PKTALIGN - 1);
204         MyRxPackets[0] -= (ulong)MyRxPackets[0] % PKTALIGN;
205         for (i = 1; i < HDLC_PKTBUFSRX; i++)
206                 MyRxPackets[i] = MyRxPackets[0] + i * PKT_MAXBLR_SIZE;
207
208         bdp = &rtx->rxbd[0];
209         for (i = 0; i < HDLC_PKTBUFSRX; i++) {
210                 bdp->cbd_sc = BD_SC_EMPTY;
211                 /* Leave space at the start for INET header. */
212                 bdp->cbd_bufaddr = (unsigned int)(MyRxPackets[i] +
213                         INET_HDR_ALIGN);
214                 bdp++;
215         }
216         bdp--;
217         bdp->cbd_sc |= BD_SC_WRAP;
218 #else
219         keymile_hdlc_enet_init_bds(rtx);
220 #endif
221
222         /* Let's re-initialize the channel now.  We have to do it later
223          * than the manual describes because we have just now finished
224          * the BD initialization.
225          */
226         cp->cp_cpcr = mk_cr_cmd(MGS_CPM_CR_HDLC, CPM_CR_INIT_TRX) | CPM_CR_FLG;
227         while (cp->cp_cpcr & CPM_CR_FLG);
228
229         sccp->scc_gsmrl = SCC_GSMRL_MODE_HDLC;
230         /* CTSS=1 */
231         sccp->scc_gsmrh = SCC_GSMRH_CTSS;
232         /* NOF=0, RTE=1, DRT=0, BUS=1 */
233         sccp->scc_psmr = ((0x8000 >> 6) | (0x8000 >> 10));
234
235 /* loopback for local testing */
236 #ifdef GJTEST
237         dprintf("LOOPBACK!\n");
238         sccp->scc_gsmrl |= SCC_GSMRL_DIAG_LOOP;
239 #endif
240
241         /*
242          * Disable all interrupts and clear all pending
243          * events.
244          */
245         sccp->scc_sccm = 0;
246         sccp->scc_scce = 0xffff;
247
248         /*
249          * And last, enable the transmit and receive processing.
250          */
251         sccp->scc_gsmrl |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT);
252
253         dprintf("%s: HDLC ENET Version 0.3 on SCC%d\n", dev->name,
254                 MGS_SCC_HDLC + 1);
255
256         /*
257          * We may not get an ARP packet because ARP was already done on
258          * a different interface, so initialize the cached values now.
259          */
260         initCachedNumbers(1);
261
262         already_inited = 1;
263
264         return 0;
265 }
266
267 void keymile_hdlc_enet_halt(struct eth_device *dev)
268 {
269 #if 0 /* just return, but keep this for reference */
270         volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
271
272         /* maybe should do a graceful stop here? */
273         immr->im_cpm.cp_scc[MGS_SCC_HDLC].scc_gsmrl &=
274                 ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
275 #endif
276 }
277
278 #endif /* CONFIG_KEYMILE_HDLC_ENET */