xref: /netbsd-src/sys/arch/powerpc/ibm4xx/dev/mal.c (revision 4e7cd6980945784a5920db424192dc10d2f6a15a)
1*4e7cd698Smsaitoh /* $NetBSD: mal.c,v 1.5 2023/06/19 08:40:30 msaitoh Exp $ */
22692e2e2Skiyohara /*
32692e2e2Skiyohara  * Copyright (c) 2010 KIYOHARA Takashi
42692e2e2Skiyohara  * All rights reserved.
52692e2e2Skiyohara  *
62692e2e2Skiyohara  * Redistribution and use in source and binary forms, with or without
72692e2e2Skiyohara  * modification, are permitted provided that the following conditions
82692e2e2Skiyohara  * are met:
92692e2e2Skiyohara  * 1. Redistributions of source code must retain the above copyright
102692e2e2Skiyohara  *    notice, this list of conditions and the following disclaimer.
112692e2e2Skiyohara  * 2. Redistributions in binary form must reproduce the above copyright
122692e2e2Skiyohara  *    notice, this list of conditions and the following disclaimer in the
132692e2e2Skiyohara  *    documentation and/or other materials provided with the distribution.
142692e2e2Skiyohara  *
152692e2e2Skiyohara  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
162692e2e2Skiyohara  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
172692e2e2Skiyohara  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
182692e2e2Skiyohara  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
192692e2e2Skiyohara  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
202692e2e2Skiyohara  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
212692e2e2Skiyohara  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
222692e2e2Skiyohara  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
232692e2e2Skiyohara  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
242692e2e2Skiyohara  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
252692e2e2Skiyohara  * POSSIBILITY OF SUCH DAMAGE.
262692e2e2Skiyohara  */
272692e2e2Skiyohara 
282692e2e2Skiyohara #include <sys/cdefs.h>
29*4e7cd698Smsaitoh __KERNEL_RCSID(0, "$NetBSD: mal.c,v 1.5 2023/06/19 08:40:30 msaitoh Exp $");
302692e2e2Skiyohara 
312692e2e2Skiyohara #include <sys/param.h>
322692e2e2Skiyohara #include <sys/device.h>
331fd2c684Smatt #include <sys/cpu.h>
341fd2c684Smatt #include <sys/intr.h>
352692e2e2Skiyohara 
361fd2c684Smatt #include <powerpc/ibm4xx/cpu.h>
372692e2e2Skiyohara #include <powerpc/ibm4xx/dcr4xx.h>
382692e2e2Skiyohara #include <powerpc/ibm4xx/dev/if_emacvar.h>
392692e2e2Skiyohara #include <powerpc/ibm4xx/dev/malvar.h>
402692e2e2Skiyohara #include <powerpc/ibm4xx/spr.h>
412692e2e2Skiyohara 
4229945337Smatt #define STAT_TO_CHAN(stat)	__builtin_clz(stat)
432692e2e2Skiyohara 
442692e2e2Skiyohara 
452692e2e2Skiyohara static int mal_txeob_intr(void *);
462692e2e2Skiyohara static int mal_rxeob_intr(void *);
472692e2e2Skiyohara static int mal_txde_intr(void *);
482692e2e2Skiyohara static int mal_rxde_intr(void *);
492692e2e2Skiyohara static int mal_serr_intr(void *);
502692e2e2Skiyohara 
512692e2e2Skiyohara 
522692e2e2Skiyohara const static struct maltbl {
532692e2e2Skiyohara 	int pvr;
542692e2e2Skiyohara 	int intrs[5];
552692e2e2Skiyohara 	int flags;
562692e2e2Skiyohara #define MAL_GEN2	(1<<0)	/* Generation 2 (405EX/EXr/440GP/GX/SP/SPe) */
572692e2e2Skiyohara } maltbl[] = {		/* TXEOB  RXEOB   TXDE   RXDE   SERR */
582692e2e2Skiyohara 	{ IBM405GP,	{    11,    12,    13,    14,    10  },	0 },
592692e2e2Skiyohara 	{ IBM405GPR,	{    11,    12,    13,    14,    10  },	0 },
602692e2e2Skiyohara 	{ AMCC405EX,	{    10,    11, 32+ 1, 32+ 2, 32+ 0  }, MAL_GEN2 },
612692e2e2Skiyohara };
622692e2e2Skiyohara 
632692e2e2Skiyohara /* Max channel is 4 on 440GX.  Others is 2 or 1. */
642692e2e2Skiyohara static void *iargs[4];
652692e2e2Skiyohara 
662692e2e2Skiyohara 
672692e2e2Skiyohara void
mal_attach(int pvr)682692e2e2Skiyohara mal_attach(int pvr)
692692e2e2Skiyohara {
702692e2e2Skiyohara 	int i, to;
712692e2e2Skiyohara 
722692e2e2Skiyohara 	for (i = 0; i < __arraycount(maltbl); i++)
732692e2e2Skiyohara 		if (maltbl[i].pvr == pvr)
742692e2e2Skiyohara 			break;
752692e2e2Skiyohara 	if (i == __arraycount(maltbl)) {
76*4e7cd698Smsaitoh 		aprint_error("%s: unknown pvr 0x%x\n", __func__, pvr);
772692e2e2Skiyohara 		return;
782692e2e2Skiyohara 	}
792692e2e2Skiyohara 
802692e2e2Skiyohara 	/*
812692e2e2Skiyohara 	 * Reset MAL.
822692e2e2Skiyohara 	 * We wait for the completion of reset in maximums for five seconds.
832692e2e2Skiyohara 	 */
842692e2e2Skiyohara 	mtdcr(DCR_MAL0_CFG, MAL0_CFG_SR);
852692e2e2Skiyohara 	to = 0;
862692e2e2Skiyohara 	while (mfdcr(DCR_MAL0_CFG) & MAL0_CFG_SR) {
872692e2e2Skiyohara 		if (to > 5000) {
882692e2e2Skiyohara 			aprint_error("%s: Soft reset failed\n", __func__);
892692e2e2Skiyohara 			return;
902692e2e2Skiyohara 		}
912692e2e2Skiyohara 		delay(1000);	/* delay 1m sec */
922692e2e2Skiyohara 		to++;
932692e2e2Skiyohara 	}
942692e2e2Skiyohara 
952692e2e2Skiyohara 	/* establish MAL interrupts */
960ece553eSrin 	intr_establish_xname(maltbl[i].intrs[0], IST_LEVEL, IPL_NET,
970ece553eSrin 	    mal_txeob_intr, NULL, "mal txeob");
980ece553eSrin 	intr_establish_xname(maltbl[i].intrs[1], IST_LEVEL, IPL_NET,
990ece553eSrin 	    mal_rxeob_intr, NULL, "mal rxeob");
1000ece553eSrin 	intr_establish_xname(maltbl[i].intrs[2], IST_LEVEL, IPL_NET,
1010ece553eSrin 	    mal_txde_intr, NULL, "mal txde");
1020ece553eSrin 	intr_establish_xname(maltbl[i].intrs[3], IST_LEVEL, IPL_NET,
1030ece553eSrin 	    mal_rxde_intr, NULL, "mal rxde");
1040ece553eSrin 	intr_establish_xname(maltbl[i].intrs[4], IST_LEVEL, IPL_NET,
1050ece553eSrin 	    mal_serr_intr, NULL, "mal serr");
1062692e2e2Skiyohara 
1072692e2e2Skiyohara 	/* Set the MAL configuration register */
1082692e2e2Skiyohara 	if (maltbl[i].flags & MAL_GEN2)
1092692e2e2Skiyohara 		mtdcr(DCR_MAL0_CFG,
1102692e2e2Skiyohara 		    MAL0_CFG_RMBS_32	|
1112692e2e2Skiyohara 		    MAL0_CFG_WMBS_32	|
1122692e2e2Skiyohara 		    MAL0_CFG_PLBLT	|
1132692e2e2Skiyohara 		    MAL0_CFG_EOPIE	|
1142692e2e2Skiyohara 		    MAL0_CFG_PLBB	|
1152692e2e2Skiyohara 		    MAL0_CFG_OPBBL	|
1162692e2e2Skiyohara 		    MAL0_CFG_LEA	|
1172692e2e2Skiyohara 		    MAL0_CFG_SD);
1182692e2e2Skiyohara 	else
1192692e2e2Skiyohara 		mtdcr(DCR_MAL0_CFG,
1202692e2e2Skiyohara 		    MAL0_CFG_PLBLT	|
1212692e2e2Skiyohara 		    MAL0_CFG_PLBB	|
1222692e2e2Skiyohara 		    MAL0_CFG_OPBBL	|
1232692e2e2Skiyohara 		    MAL0_CFG_LEA	|
1242692e2e2Skiyohara 		    MAL0_CFG_SD);
1252692e2e2Skiyohara 
1262692e2e2Skiyohara 	/* Enable MAL SERR Interrupt */
1272692e2e2Skiyohara 	mtdcr(DCR_MAL0_IER,
1282692e2e2Skiyohara 	    MAL0_IER_PT		|
1292692e2e2Skiyohara 	    MAL0_IER_PRE	|
1302692e2e2Skiyohara 	    MAL0_IER_PWE	|
1312692e2e2Skiyohara 	    MAL0_IER_DE		|
1322692e2e2Skiyohara 	    MAL0_IER_NWE	|
1332692e2e2Skiyohara 	    MAL0_IER_TO		|
1342692e2e2Skiyohara 	    MAL0_IER_OPB	|
1352692e2e2Skiyohara 	    MAL0_IER_PLB);
1362692e2e2Skiyohara }
1372692e2e2Skiyohara 
1382692e2e2Skiyohara static int
mal_txeob_intr(void * arg)1392692e2e2Skiyohara mal_txeob_intr(void *arg)
1402692e2e2Skiyohara {
1412692e2e2Skiyohara 	uint32_t tcei;
1422692e2e2Skiyohara 	int chan, handled = 0;
1432692e2e2Skiyohara 
1442692e2e2Skiyohara 	while ((tcei = mfdcr(DCR_MAL0_TXEOBISR))) {
1452692e2e2Skiyohara 		chan = STAT_TO_CHAN(tcei);
1462692e2e2Skiyohara 		if (iargs[chan] != NULL) {
1472692e2e2Skiyohara 			mtdcr(DCR_MAL0_TXEOBISR, MAL0__XCAR_CHAN(chan));
1482692e2e2Skiyohara 			handled |= emac_txeob_intr(iargs[chan]);
1492692e2e2Skiyohara 		}
1502692e2e2Skiyohara 	}
1512692e2e2Skiyohara 	return handled;
1522692e2e2Skiyohara }
1532692e2e2Skiyohara 
1542692e2e2Skiyohara static int
mal_rxeob_intr(void * arg)1552692e2e2Skiyohara mal_rxeob_intr(void *arg)
1562692e2e2Skiyohara {
1572692e2e2Skiyohara 	uint32_t rcei;
1582692e2e2Skiyohara 	int chan, handled = 0;
1592692e2e2Skiyohara 
1602692e2e2Skiyohara 	while ((rcei = mfdcr(DCR_MAL0_RXEOBISR))) {
1612692e2e2Skiyohara 		chan = STAT_TO_CHAN(rcei);
1622692e2e2Skiyohara 		if (iargs[chan] != NULL) {
1632692e2e2Skiyohara 			/* Clear the interrupt */
1642692e2e2Skiyohara 			mtdcr(DCR_MAL0_RXEOBISR, MAL0__XCAR_CHAN(chan));
1652692e2e2Skiyohara 
1662692e2e2Skiyohara 			handled |= emac_rxeob_intr(iargs[chan]);
1672692e2e2Skiyohara 		}
1682692e2e2Skiyohara 	}
1692692e2e2Skiyohara 	return handled;
1702692e2e2Skiyohara }
1712692e2e2Skiyohara 
1722692e2e2Skiyohara static int
mal_txde_intr(void * arg)1732692e2e2Skiyohara mal_txde_intr(void *arg)
1742692e2e2Skiyohara {
1752692e2e2Skiyohara 	uint32_t txde;
1762692e2e2Skiyohara 	int chan, handled = 0;
1772692e2e2Skiyohara 
1782692e2e2Skiyohara 	while ((txde = mfdcr(DCR_MAL0_TXDEIR))) {
1792692e2e2Skiyohara 		chan = STAT_TO_CHAN(txde);
1802692e2e2Skiyohara 		if (iargs[chan] != NULL) {
1812692e2e2Skiyohara 			handled |= emac_txde_intr(iargs[chan]);
1822692e2e2Skiyohara 
1832692e2e2Skiyohara 			/* Clear the interrupt */
1842692e2e2Skiyohara 			mtdcr(DCR_MAL0_TXDEIR, MAL0__XCAR_CHAN(chan));
1852692e2e2Skiyohara 		}
1862692e2e2Skiyohara 	}
1872692e2e2Skiyohara 	return handled;
1882692e2e2Skiyohara }
1892692e2e2Skiyohara 
1902692e2e2Skiyohara static int
mal_rxde_intr(void * arg)1912692e2e2Skiyohara mal_rxde_intr(void *arg)
1922692e2e2Skiyohara {
1932692e2e2Skiyohara 	uint32_t rxde;
1942692e2e2Skiyohara 	int chan, handled = 0;
1952692e2e2Skiyohara 
1962692e2e2Skiyohara 	while ((rxde = mfdcr(DCR_MAL0_RXDEIR))) {
1972692e2e2Skiyohara 		chan = STAT_TO_CHAN(rxde);
1982692e2e2Skiyohara 		if (iargs[chan] != NULL) {
1992692e2e2Skiyohara 			handled |= emac_rxde_intr(iargs[chan]);
2002692e2e2Skiyohara 
2012692e2e2Skiyohara 			/* Clear the interrupt */
2022692e2e2Skiyohara 			mtdcr(DCR_MAL0_RXDEIR, MAL0__XCAR_CHAN(chan));
2032692e2e2Skiyohara 
2042692e2e2Skiyohara 		        /* Reenable the receive channel */
2052692e2e2Skiyohara 			mtdcr(DCR_MAL0_RXCASR, MAL0__XCAR_CHAN(chan));
2062692e2e2Skiyohara 		}
2072692e2e2Skiyohara 	}
2082692e2e2Skiyohara 	return handled;
2092692e2e2Skiyohara }
2102692e2e2Skiyohara 
2112692e2e2Skiyohara static int
mal_serr_intr(void * arg)2122692e2e2Skiyohara mal_serr_intr(void *arg)
2132692e2e2Skiyohara {
2142692e2e2Skiyohara 	uint32_t esr;
2152692e2e2Skiyohara 
2162692e2e2Skiyohara 	esr = mfdcr(DCR_MAL0_ESR);
2172692e2e2Skiyohara 
2182692e2e2Skiyohara 	/* not yet... */
2192692e2e2Skiyohara 	aprint_error("MAL SERR: ESR 0x%08x\n", esr);
2202692e2e2Skiyohara 
2212692e2e2Skiyohara 	/* Clear the interrupt status bits. */
2222692e2e2Skiyohara 	mtdcr(DCR_MAL0_ESR, esr);
2232692e2e2Skiyohara 
2242692e2e2Skiyohara 	return 1;
2252692e2e2Skiyohara }
2262692e2e2Skiyohara 
2272692e2e2Skiyohara 
2282692e2e2Skiyohara void
mal_intr_establish(int chan,void * arg)2292692e2e2Skiyohara mal_intr_establish(int chan, void *arg)
2302692e2e2Skiyohara {
2312692e2e2Skiyohara 
2322692e2e2Skiyohara 	if (chan >= __arraycount(iargs))
2332692e2e2Skiyohara 		panic("MAL channel %d not support (max %d)\n",
2342692e2e2Skiyohara 		    chan, __arraycount(iargs));
2352692e2e2Skiyohara 
2362692e2e2Skiyohara 	iargs[chan] = arg;
2372692e2e2Skiyohara }
2382692e2e2Skiyohara 
2392692e2e2Skiyohara int
mal_start(int chan,uint32_t cdtxaddr,uint32_t cdrxaddr)2402692e2e2Skiyohara mal_start(int chan, uint32_t cdtxaddr, uint32_t cdrxaddr)
2412692e2e2Skiyohara {
2422692e2e2Skiyohara 
2432692e2e2Skiyohara 	/*
2442692e2e2Skiyohara 	 * Give the transmit and receive rings to the MAL.
2452692e2e2Skiyohara 	 * And set the receive channel buffer size (in units of 16 bytes).
2462692e2e2Skiyohara 	 */
2472692e2e2Skiyohara #if MCLBYTES > (4096 - 16)	/* XXX! */
2482692e2e2Skiyohara # error MCLBYTES > max rx channel buffer size
2492692e2e2Skiyohara #endif
2502692e2e2Skiyohara         /* The mtdcr() allows only the constant in the first argument... */
2512692e2e2Skiyohara 	switch (chan) {
2522692e2e2Skiyohara 	case 0:
2532692e2e2Skiyohara 		mtdcr(DCR_MAL0_TXCTP0R, cdtxaddr);
2542692e2e2Skiyohara 		mtdcr(DCR_MAL0_RXCTP0R, cdrxaddr);
2552692e2e2Skiyohara 		mtdcr(DCR_MAL0_RCBS0, MCLBYTES / 16);
2562692e2e2Skiyohara 		break;
2572692e2e2Skiyohara 
2582692e2e2Skiyohara 	case 1:
2592692e2e2Skiyohara 		mtdcr(DCR_MAL0_TXCTP1R, cdtxaddr);
2602692e2e2Skiyohara 		mtdcr(DCR_MAL0_RXCTP1R, cdrxaddr);
2612692e2e2Skiyohara 		mtdcr(DCR_MAL0_RCBS1, MCLBYTES / 16);
2622692e2e2Skiyohara 		break;
2632692e2e2Skiyohara 
2642692e2e2Skiyohara 	case 2:
2652692e2e2Skiyohara 		mtdcr(DCR_MAL0_TXCTP2R, cdtxaddr);
2662692e2e2Skiyohara 		mtdcr(DCR_MAL0_RXCTP2R, cdrxaddr);
2672692e2e2Skiyohara 		mtdcr(DCR_MAL0_RCBS2, MCLBYTES / 16);
2682692e2e2Skiyohara 		break;
2692692e2e2Skiyohara 
2702692e2e2Skiyohara 	case 3:
2712692e2e2Skiyohara 		mtdcr(DCR_MAL0_TXCTP3R, cdtxaddr);
2722692e2e2Skiyohara 		mtdcr(DCR_MAL0_RXCTP3R, cdrxaddr);
2732692e2e2Skiyohara 		mtdcr(DCR_MAL0_RCBS3, MCLBYTES / 16);
2742692e2e2Skiyohara 		break;
2752692e2e2Skiyohara 
2762692e2e2Skiyohara 	default:
2772692e2e2Skiyohara 		aprint_error("MAL unknown channel no.%d\n", chan);
2782692e2e2Skiyohara 		return EINVAL;
2792692e2e2Skiyohara 	}
2802692e2e2Skiyohara 
2812692e2e2Skiyohara 	/* Enable the transmit and receive channel on the MAL. */
2822692e2e2Skiyohara 	mtdcr(DCR_MAL0_RXCASR, MAL0__XCAR_CHAN(chan));
2832692e2e2Skiyohara 	mtdcr(DCR_MAL0_TXCASR, MAL0__XCAR_CHAN(chan));
2842692e2e2Skiyohara 
2852692e2e2Skiyohara 	return 0;
2862692e2e2Skiyohara }
2872692e2e2Skiyohara 
2882692e2e2Skiyohara void
mal_stop(int chan)2892692e2e2Skiyohara mal_stop(int chan)
2902692e2e2Skiyohara {
2912692e2e2Skiyohara 
2922692e2e2Skiyohara 	/* Disable the receive and transmit channels. */
2932692e2e2Skiyohara 	mtdcr(DCR_MAL0_RXCARR, MAL0__XCAR_CHAN(chan));
2942692e2e2Skiyohara 	mtdcr(DCR_MAL0_TXCARR, MAL0__XCAR_CHAN(chan));
2952692e2e2Skiyohara }
296