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