1/* $NetBSD: mal.c,v 1.2 2011/06/18 06:41:42 matt 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.2 2011/06/18 06:41:42 matt 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 45static int mal_txeob_intr(void *); 46static int mal_rxeob_intr(void *); 47static int mal_txde_intr(void *); 48static int mal_rxde_intr(void *); 49static int mal_serr_intr(void *); 50 51 52const 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. */ 64static void *iargs[4]; 65 66 67void 68mal_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: unknwon 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(maltbl[i].intrs[0], IST_LEVEL, IPL_NET, 97 mal_txeob_intr, NULL); 98 intr_establish(maltbl[i].intrs[1], IST_LEVEL, IPL_NET, 99 mal_rxeob_intr, NULL); 100 intr_establish(maltbl[i].intrs[2], IST_LEVEL, IPL_NET, 101 mal_txde_intr, NULL); 102 intr_establish(maltbl[i].intrs[3], IST_LEVEL, IPL_NET, 103 mal_rxde_intr, NULL); 104 intr_establish(maltbl[i].intrs[4], IST_LEVEL, IPL_NET, 105 mal_serr_intr, NULL); 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 138static int 139mal_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 154static int 155mal_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 172static int 173mal_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 190static int 191mal_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 211static int 212mal_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 228void 229mal_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 239int 240mal_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 288void 289mal_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