xref: /netbsd-src/sys/arch/powerpc/ibm4xx/dev/mal.c (revision 4e7cd6980945784a5920db424192dc10d2f6a15a)
1 /* $NetBSD: mal.c,v 1.5 2023/06/19 08:40:30 msaitoh Exp $ */
2 /*
3  * Copyright (c) 2010 KIYOHARA Takashi
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
19  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
23  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
24  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25  * POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #include <sys/cdefs.h>
29 __KERNEL_RCSID(0, "$NetBSD: mal.c,v 1.5 2023/06/19 08:40:30 msaitoh Exp $");
30 
31 #include <sys/param.h>
32 #include <sys/device.h>
33 #include <sys/cpu.h>
34 #include <sys/intr.h>
35 
36 #include <powerpc/ibm4xx/cpu.h>
37 #include <powerpc/ibm4xx/dcr4xx.h>
38 #include <powerpc/ibm4xx/dev/if_emacvar.h>
39 #include <powerpc/ibm4xx/dev/malvar.h>
40 #include <powerpc/ibm4xx/spr.h>
41 
42 #define STAT_TO_CHAN(stat)	__builtin_clz(stat)
43 
44 
45 static int mal_txeob_intr(void *);
46 static int mal_rxeob_intr(void *);
47 static int mal_txde_intr(void *);
48 static int mal_rxde_intr(void *);
49 static int mal_serr_intr(void *);
50 
51 
52 const static struct maltbl {
53 	int pvr;
54 	int intrs[5];
55 	int flags;
56 #define MAL_GEN2	(1<<0)	/* Generation 2 (405EX/EXr/440GP/GX/SP/SPe) */
57 } maltbl[] = {		/* TXEOB  RXEOB   TXDE   RXDE   SERR */
58 	{ IBM405GP,	{    11,    12,    13,    14,    10  },	0 },
59 	{ IBM405GPR,	{    11,    12,    13,    14,    10  },	0 },
60 	{ AMCC405EX,	{    10,    11, 32+ 1, 32+ 2, 32+ 0  }, MAL_GEN2 },
61 };
62 
63 /* Max channel is 4 on 440GX.  Others is 2 or 1. */
64 static void *iargs[4];
65 
66 
67 void
mal_attach(int pvr)68 mal_attach(int pvr)
69 {
70 	int i, to;
71 
72 	for (i = 0; i < __arraycount(maltbl); i++)
73 		if (maltbl[i].pvr == pvr)
74 			break;
75 	if (i == __arraycount(maltbl)) {
76 		aprint_error("%s: unknown pvr 0x%x\n", __func__, pvr);
77 		return;
78 	}
79 
80 	/*
81 	 * Reset MAL.
82 	 * We wait for the completion of reset in maximums for five seconds.
83 	 */
84 	mtdcr(DCR_MAL0_CFG, MAL0_CFG_SR);
85 	to = 0;
86 	while (mfdcr(DCR_MAL0_CFG) & MAL0_CFG_SR) {
87 		if (to > 5000) {
88 			aprint_error("%s: Soft reset failed\n", __func__);
89 			return;
90 		}
91 		delay(1000);	/* delay 1m sec */
92 		to++;
93 	}
94 
95 	/* establish MAL interrupts */
96 	intr_establish_xname(maltbl[i].intrs[0], IST_LEVEL, IPL_NET,
97 	    mal_txeob_intr, NULL, "mal txeob");
98 	intr_establish_xname(maltbl[i].intrs[1], IST_LEVEL, IPL_NET,
99 	    mal_rxeob_intr, NULL, "mal rxeob");
100 	intr_establish_xname(maltbl[i].intrs[2], IST_LEVEL, IPL_NET,
101 	    mal_txde_intr, NULL, "mal txde");
102 	intr_establish_xname(maltbl[i].intrs[3], IST_LEVEL, IPL_NET,
103 	    mal_rxde_intr, NULL, "mal rxde");
104 	intr_establish_xname(maltbl[i].intrs[4], IST_LEVEL, IPL_NET,
105 	    mal_serr_intr, NULL, "mal serr");
106 
107 	/* Set the MAL configuration register */
108 	if (maltbl[i].flags & MAL_GEN2)
109 		mtdcr(DCR_MAL0_CFG,
110 		    MAL0_CFG_RMBS_32	|
111 		    MAL0_CFG_WMBS_32	|
112 		    MAL0_CFG_PLBLT	|
113 		    MAL0_CFG_EOPIE	|
114 		    MAL0_CFG_PLBB	|
115 		    MAL0_CFG_OPBBL	|
116 		    MAL0_CFG_LEA	|
117 		    MAL0_CFG_SD);
118 	else
119 		mtdcr(DCR_MAL0_CFG,
120 		    MAL0_CFG_PLBLT	|
121 		    MAL0_CFG_PLBB	|
122 		    MAL0_CFG_OPBBL	|
123 		    MAL0_CFG_LEA	|
124 		    MAL0_CFG_SD);
125 
126 	/* Enable MAL SERR Interrupt */
127 	mtdcr(DCR_MAL0_IER,
128 	    MAL0_IER_PT		|
129 	    MAL0_IER_PRE	|
130 	    MAL0_IER_PWE	|
131 	    MAL0_IER_DE		|
132 	    MAL0_IER_NWE	|
133 	    MAL0_IER_TO		|
134 	    MAL0_IER_OPB	|
135 	    MAL0_IER_PLB);
136 }
137 
138 static int
mal_txeob_intr(void * arg)139 mal_txeob_intr(void *arg)
140 {
141 	uint32_t tcei;
142 	int chan, handled = 0;
143 
144 	while ((tcei = mfdcr(DCR_MAL0_TXEOBISR))) {
145 		chan = STAT_TO_CHAN(tcei);
146 		if (iargs[chan] != NULL) {
147 			mtdcr(DCR_MAL0_TXEOBISR, MAL0__XCAR_CHAN(chan));
148 			handled |= emac_txeob_intr(iargs[chan]);
149 		}
150 	}
151 	return handled;
152 }
153 
154 static int
mal_rxeob_intr(void * arg)155 mal_rxeob_intr(void *arg)
156 {
157 	uint32_t rcei;
158 	int chan, handled = 0;
159 
160 	while ((rcei = mfdcr(DCR_MAL0_RXEOBISR))) {
161 		chan = STAT_TO_CHAN(rcei);
162 		if (iargs[chan] != NULL) {
163 			/* Clear the interrupt */
164 			mtdcr(DCR_MAL0_RXEOBISR, MAL0__XCAR_CHAN(chan));
165 
166 			handled |= emac_rxeob_intr(iargs[chan]);
167 		}
168 	}
169 	return handled;
170 }
171 
172 static int
mal_txde_intr(void * arg)173 mal_txde_intr(void *arg)
174 {
175 	uint32_t txde;
176 	int chan, handled = 0;
177 
178 	while ((txde = mfdcr(DCR_MAL0_TXDEIR))) {
179 		chan = STAT_TO_CHAN(txde);
180 		if (iargs[chan] != NULL) {
181 			handled |= emac_txde_intr(iargs[chan]);
182 
183 			/* Clear the interrupt */
184 			mtdcr(DCR_MAL0_TXDEIR, MAL0__XCAR_CHAN(chan));
185 		}
186 	}
187 	return handled;
188 }
189 
190 static int
mal_rxde_intr(void * arg)191 mal_rxde_intr(void *arg)
192 {
193 	uint32_t rxde;
194 	int chan, handled = 0;
195 
196 	while ((rxde = mfdcr(DCR_MAL0_RXDEIR))) {
197 		chan = STAT_TO_CHAN(rxde);
198 		if (iargs[chan] != NULL) {
199 			handled |= emac_rxde_intr(iargs[chan]);
200 
201 			/* Clear the interrupt */
202 			mtdcr(DCR_MAL0_RXDEIR, MAL0__XCAR_CHAN(chan));
203 
204 		        /* Reenable the receive channel */
205 			mtdcr(DCR_MAL0_RXCASR, MAL0__XCAR_CHAN(chan));
206 		}
207 	}
208 	return handled;
209 }
210 
211 static int
mal_serr_intr(void * arg)212 mal_serr_intr(void *arg)
213 {
214 	uint32_t esr;
215 
216 	esr = mfdcr(DCR_MAL0_ESR);
217 
218 	/* not yet... */
219 	aprint_error("MAL SERR: ESR 0x%08x\n", esr);
220 
221 	/* Clear the interrupt status bits. */
222 	mtdcr(DCR_MAL0_ESR, esr);
223 
224 	return 1;
225 }
226 
227 
228 void
mal_intr_establish(int chan,void * arg)229 mal_intr_establish(int chan, void *arg)
230 {
231 
232 	if (chan >= __arraycount(iargs))
233 		panic("MAL channel %d not support (max %d)\n",
234 		    chan, __arraycount(iargs));
235 
236 	iargs[chan] = arg;
237 }
238 
239 int
mal_start(int chan,uint32_t cdtxaddr,uint32_t cdrxaddr)240 mal_start(int chan, uint32_t cdtxaddr, uint32_t cdrxaddr)
241 {
242 
243 	/*
244 	 * Give the transmit and receive rings to the MAL.
245 	 * And set the receive channel buffer size (in units of 16 bytes).
246 	 */
247 #if MCLBYTES > (4096 - 16)	/* XXX! */
248 # error MCLBYTES > max rx channel buffer size
249 #endif
250         /* The mtdcr() allows only the constant in the first argument... */
251 	switch (chan) {
252 	case 0:
253 		mtdcr(DCR_MAL0_TXCTP0R, cdtxaddr);
254 		mtdcr(DCR_MAL0_RXCTP0R, cdrxaddr);
255 		mtdcr(DCR_MAL0_RCBS0, MCLBYTES / 16);
256 		break;
257 
258 	case 1:
259 		mtdcr(DCR_MAL0_TXCTP1R, cdtxaddr);
260 		mtdcr(DCR_MAL0_RXCTP1R, cdrxaddr);
261 		mtdcr(DCR_MAL0_RCBS1, MCLBYTES / 16);
262 		break;
263 
264 	case 2:
265 		mtdcr(DCR_MAL0_TXCTP2R, cdtxaddr);
266 		mtdcr(DCR_MAL0_RXCTP2R, cdrxaddr);
267 		mtdcr(DCR_MAL0_RCBS2, MCLBYTES / 16);
268 		break;
269 
270 	case 3:
271 		mtdcr(DCR_MAL0_TXCTP3R, cdtxaddr);
272 		mtdcr(DCR_MAL0_RXCTP3R, cdrxaddr);
273 		mtdcr(DCR_MAL0_RCBS3, MCLBYTES / 16);
274 		break;
275 
276 	default:
277 		aprint_error("MAL unknown channel no.%d\n", chan);
278 		return EINVAL;
279 	}
280 
281 	/* Enable the transmit and receive channel on the MAL. */
282 	mtdcr(DCR_MAL0_RXCASR, MAL0__XCAR_CHAN(chan));
283 	mtdcr(DCR_MAL0_TXCASR, MAL0__XCAR_CHAN(chan));
284 
285 	return 0;
286 }
287 
288 void
mal_stop(int chan)289 mal_stop(int chan)
290 {
291 
292 	/* Disable the receive and transmit channels. */
293 	mtdcr(DCR_MAL0_RXCARR, MAL0__XCAR_CHAN(chan));
294 	mtdcr(DCR_MAL0_TXCARR, MAL0__XCAR_CHAN(chan));
295 }
296