Home | History | Annotate | Download | only in shared
      1 /*
      2  * Misc utility routines for accessing chip-specific features
      3  * of the SiliconBackplane-based Broadcom chips.
      4  *
      5  * Copyright (C) 1999-2010, Broadcom Corporation
      6  *
      7  *      Unless you and Broadcom execute a separate written software license
      8  * agreement governing use of this software, this software is licensed to you
      9  * under the terms of the GNU General Public License version 2 (the "GPL"),
     10  * available at http://www.broadcom.com/licenses/GPLv2.php, with the
     11  * following added to such license:
     12  *
     13  *      As a special exception, the copyright holders of this software give you
     14  * permission to link this software with independent modules, and to copy and
     15  * distribute the resulting executable under terms of your choice, provided that
     16  * you also meet, for each linked independent module, the terms and conditions of
     17  * the license of that module.  An independent module is a module which is not
     18  * derived from this software.  The special exception does not apply to any
     19  * modifications of the software.
     20  *
     21  *      Notwithstanding the above, under no circumstances may you combine this
     22  * software in any way with any other Broadcom software provided under a license
     23  * other than the GPL, without Broadcom's express prior written consent.
     24  *
     25  * $Id: aiutils.c,v 1.6.4.7.4.6 2010/04/21 20:43:47 Exp $
     26  */
     27 
     28 #include <typedefs.h>
     29 #include <bcmdefs.h>
     30 #include <osl.h>
     31 #include <bcmutils.h>
     32 #include <siutils.h>
     33 #include <hndsoc.h>
     34 #include <sbchipc.h>
     35 #include <pcicfg.h>
     36 
     37 #include "siutils_priv.h"
     38 
     39 STATIC uint32
     40 get_asd(si_t *sih, uint32 *eromptr, uint sp, uint ad, uint st,
     41 	uint32 *addrl, uint32 *addrh, uint32 *sizel, uint32 *sizeh);
     42 
     43 
     44 /* EROM parsing */
     45 
     46 static uint32
     47 get_erom_ent(si_t *sih, uint32 *eromptr, uint32 mask, uint32 match)
     48 {
     49 	uint32 ent;
     50 	uint inv = 0, nom = 0;
     51 
     52 	while (TRUE) {
     53 		ent = R_REG(si_osh(sih), (uint32 *)(uintptr)(*eromptr));
     54 		*eromptr += sizeof(uint32);
     55 
     56 		if (mask == 0)
     57 			break;
     58 
     59 		if ((ent & ER_VALID) == 0) {
     60 			inv++;
     61 			continue;
     62 		}
     63 
     64 		if (ent == (ER_END | ER_VALID))
     65 			break;
     66 
     67 		if ((ent & mask) == match)
     68 			break;
     69 
     70 		nom++;
     71 	}
     72 
     73 	SI_MSG(("%s: Returning ent 0x%08x\n", __FUNCTION__, ent));
     74 	if (inv + nom)
     75 		SI_MSG(("  after %d invalid and %d non-matching entries\n", inv, nom));
     76 	return ent;
     77 }
     78 
     79 STATIC uint32
     80 get_asd(si_t *sih, uint32 *eromptr, uint sp, uint ad, uint st,
     81 	uint32 *addrl, uint32 *addrh, uint32 *sizel, uint32 *sizeh)
     82 {
     83 	uint32 asd, sz, szd;
     84 
     85 	asd = get_erom_ent(sih, eromptr, ER_VALID, ER_VALID);
     86 	if (((asd & ER_TAG1) != ER_ADD) ||
     87 	    (((asd & AD_SP_MASK) >> AD_SP_SHIFT) != sp) ||
     88 	    ((asd & AD_ST_MASK) != st)) {
     89 		/* This is not what we want, "push" it back */
     90 		*eromptr -= sizeof(uint32);
     91 		return 0;
     92 	}
     93 	*addrl = asd & AD_ADDR_MASK;
     94 	if (asd & AD_AG32)
     95 		*addrh = get_erom_ent(sih, eromptr, 0, 0);
     96 	else
     97 		*addrh = 0;
     98 	*sizeh = 0;
     99 	sz = asd & AD_SZ_MASK;
    100 	if (sz == AD_SZ_SZD) {
    101 		szd = get_erom_ent(sih, eromptr, 0, 0);
    102 		*sizel = szd & SD_SZ_MASK;
    103 		if (szd & SD_SG32)
    104 			*sizeh = get_erom_ent(sih, eromptr, 0, 0);
    105 	} else
    106 		*sizel = AD_SZ_BASE << (sz >> AD_SZ_SHIFT);
    107 
    108 	SI_MSG(("  SP %d, ad %d: st = %d, 0x%08x_0x%08x @ 0x%08x_0x%08x\n",
    109 	        sp, ad, st, *sizeh, *sizel, *addrh, *addrl));
    110 
    111 	return asd;
    112 }
    113 
    114 /* parse the enumeration rom to identify all cores */
    115 void
    116 ai_scan(si_t *sih, void *regs, uint devid)
    117 {
    118 	si_info_t *sii = SI_INFO(sih);
    119 	chipcregs_t *cc = (chipcregs_t *)regs;
    120 	uint32 erombase, eromptr, eromlim;
    121 
    122 	erombase = R_REG(sii->osh, &cc->eromptr);
    123 
    124 	switch (BUSTYPE(sih->bustype)) {
    125 	case SI_BUS:
    126 		eromptr = (uintptr)REG_MAP(erombase, SI_CORE_SIZE);
    127 		break;
    128 
    129 	case PCI_BUS:
    130 		/* Set wrappers address */
    131 		sii->curwrap = (void *)((uintptr)regs + SI_CORE_SIZE);
    132 
    133 		/* Now point the window at the erom */
    134 		OSL_PCI_WRITE_CONFIG(sii->osh, PCI_BAR0_WIN, 4, erombase);
    135 		eromptr = (uint32)(uintptr)regs;
    136 		break;
    137 
    138 	case SPI_BUS:
    139 	case SDIO_BUS:
    140 		eromptr = erombase;
    141 		break;
    142 
    143 	case PCMCIA_BUS:
    144 	default:
    145 		SI_ERROR(("Don't know how to do AXI enumertion on bus %d\n", sih->bustype));
    146 		ASSERT(0);
    147 		return;
    148 	}
    149 	eromlim = eromptr + ER_REMAPCONTROL;
    150 
    151 	SI_MSG(("ai_scan: regs = 0x%p, erombase = 0x%08x, eromptr = 0x%08x, eromlim = 0x%08x\n",
    152 	        regs, erombase, eromptr, eromlim));
    153 	while (eromptr < eromlim) {
    154 		uint32 cia, cib, base, cid, mfg, crev, nmw, nsw, nmp, nsp;
    155 		uint32 mpd, asd, addrl, addrh, sizel, sizeh;
    156 		uint i, j, idx;
    157 		bool br;
    158 
    159 		br = FALSE;
    160 
    161 		/* Grok a component */
    162 		cia = get_erom_ent(sih, &eromptr, ER_TAG, ER_CI);
    163 		if (cia == (ER_END | ER_VALID)) {
    164 			SI_MSG(("Found END of erom after %d cores\n", sii->numcores));
    165 			return;
    166 		}
    167 		base = eromptr - sizeof(uint32);
    168 		cib = get_erom_ent(sih, &eromptr, 0, 0);
    169 
    170 		if ((cib & ER_TAG) != ER_CI) {
    171 			SI_ERROR(("CIA not followed by CIB\n"));
    172 			goto error;
    173 		}
    174 
    175 		cid = (cia & CIA_CID_MASK) >> CIA_CID_SHIFT;
    176 		mfg = (cia & CIA_MFG_MASK) >> CIA_MFG_SHIFT;
    177 		crev = (cib & CIB_REV_MASK) >> CIB_REV_SHIFT;
    178 		nmw = (cib & CIB_NMW_MASK) >> CIB_NMW_SHIFT;
    179 		nsw = (cib & CIB_NSW_MASK) >> CIB_NSW_SHIFT;
    180 		nmp = (cib & CIB_NMP_MASK) >> CIB_NMP_SHIFT;
    181 		nsp = (cib & CIB_NSP_MASK) >> CIB_NSP_SHIFT;
    182 
    183 		SI_MSG(("Found component 0x%04x/0x%4x rev %d at erom addr 0x%08x, with nmw = %d, "
    184 		        "nsw = %d, nmp = %d & nsp = %d\n",
    185 		        mfg, cid, crev, base, nmw, nsw, nmp, nsp));
    186 
    187 		if (((mfg == MFGID_ARM) && (cid == DEF_AI_COMP)) || (nsp == 0))
    188 			continue;
    189 		if ((nmw + nsw == 0)) {
    190 			/* A component which is not a core */
    191 			if (cid == OOB_ROUTER_CORE_ID) {
    192 				asd = get_asd(sih, &eromptr, 0, 0, AD_ST_SLAVE,
    193 					&addrl, &addrh, &sizel, &sizeh);
    194 				if (asd != 0) {
    195 					sii->common_info->oob_router = addrl;
    196 				}
    197 			}
    198 			continue;
    199 		}
    200 
    201 		idx = sii->numcores;
    202 /*		sii->eromptr[idx] = base; */
    203 		sii->common_info->cia[idx] = cia;
    204 		sii->common_info->cib[idx] = cib;
    205 		sii->common_info->coreid[idx] = cid;
    206 
    207 		for (i = 0; i < nmp; i++) {
    208 			mpd = get_erom_ent(sih, &eromptr, ER_VALID, ER_VALID);
    209 			if ((mpd & ER_TAG) != ER_MP) {
    210 				SI_ERROR(("Not enough MP entries for component 0x%x\n", cid));
    211 				goto error;
    212 			}
    213 			SI_MSG(("  Master port %d, mp: %d id: %d\n", i,
    214 			        (mpd & MPD_MP_MASK) >> MPD_MP_SHIFT,
    215 			        (mpd & MPD_MUI_MASK) >> MPD_MUI_SHIFT));
    216 		}
    217 
    218 		/* First Slave Address Descriptor should be port 0:
    219 		 * the main register space for the core
    220 		 */
    221 		asd = get_asd(sih, &eromptr, 0, 0, AD_ST_SLAVE, &addrl, &addrh, &sizel, &sizeh);
    222 		if (asd == 0) {
    223 			/* Try again to see if it is a bridge */
    224 			asd = get_asd(sih, &eromptr, 0, 0, AD_ST_BRIDGE, &addrl, &addrh,
    225 			              &sizel, &sizeh);
    226 			if (asd != 0)
    227 				br = TRUE;
    228 			else
    229 				if ((addrh != 0) || (sizeh != 0) || (sizel != SI_CORE_SIZE)) {
    230 					SI_ERROR(("First Slave ASD for core 0x%04x malformed "
    231 					          "(0x%08x)\n", cid, asd));
    232 					goto error;
    233 				}
    234 		}
    235 		sii->common_info->coresba[idx] = addrl;
    236 		sii->common_info->coresba_size[idx] = sizel;
    237 		/* Get any more ASDs in port 0 */
    238 		j = 1;
    239 		do {
    240 			asd = get_asd(sih, &eromptr, 0, j, AD_ST_SLAVE, &addrl, &addrh,
    241 			              &sizel, &sizeh);
    242 			if ((asd != 0) && (j == 1) && (sizel == SI_CORE_SIZE))
    243 				sii->common_info->coresba2[idx] = addrl;
    244 				sii->common_info->coresba2_size[idx] = sizel;
    245 			j++;
    246 		} while (asd != 0);
    247 
    248 		/* Go through the ASDs for other slave ports */
    249 		for (i = 1; i < nsp; i++) {
    250 			j = 0;
    251 			do {
    252 				asd = get_asd(sih, &eromptr, i, j++, AD_ST_SLAVE, &addrl, &addrh,
    253 				              &sizel, &sizeh);
    254 			} while (asd != 0);
    255 			if (j == 0) {
    256 				SI_ERROR((" SP %d has no address descriptors\n", i));
    257 				goto error;
    258 			}
    259 		}
    260 
    261 		/* Now get master wrappers */
    262 		for (i = 0; i < nmw; i++) {
    263 			asd = get_asd(sih, &eromptr, i, 0, AD_ST_MWRAP, &addrl, &addrh,
    264 			              &sizel, &sizeh);
    265 			if (asd == 0) {
    266 				SI_ERROR(("Missing descriptor for MW %d\n", i));
    267 				goto error;
    268 			}
    269 			if ((sizeh != 0) || (sizel != SI_CORE_SIZE)) {
    270 				SI_ERROR(("Master wrapper %d is not 4KB\n", i));
    271 				goto error;
    272 			}
    273 			if (i == 0)
    274 				sii->common_info->wrapba[idx] = addrl;
    275 		}
    276 
    277 		/* And finally slave wrappers */
    278 		for (i = 0; i < nsw; i++) {
    279 			uint fwp = (nsp == 1) ? 0 : 1;
    280 			asd = get_asd(sih, &eromptr, fwp + i, 0, AD_ST_SWRAP, &addrl, &addrh,
    281 			              &sizel, &sizeh);
    282 			if (asd == 0) {
    283 				SI_ERROR(("Missing descriptor for SW %d\n", i));
    284 				goto error;
    285 			}
    286 			if ((sizeh != 0) || (sizel != SI_CORE_SIZE)) {
    287 				SI_ERROR(("Slave wrapper %d is not 4KB\n", i));
    288 				goto error;
    289 			}
    290 			if ((nmw == 0) && (i == 0))
    291 				sii->common_info->wrapba[idx] = addrl;
    292 		}
    293 
    294 		/* Don't record bridges */
    295 		if (br)
    296 			continue;
    297 
    298 		/* Done with core */
    299 		sii->numcores++;
    300 	}
    301 
    302 	SI_ERROR(("Reached end of erom without finding END"));
    303 
    304 error:
    305 	sii->numcores = 0;
    306 	return;
    307 }
    308 
    309 /* This function changes the logical "focus" to the indicated core.
    310  * Return the current core's virtual address.
    311  */
    312 void *
    313 ai_setcoreidx(si_t *sih, uint coreidx)
    314 {
    315 	si_info_t *sii = SI_INFO(sih);
    316 	uint32 addr = sii->common_info->coresba[coreidx];
    317 	uint32 wrap = sii->common_info->wrapba[coreidx];
    318 	void *regs;
    319 
    320 	if (coreidx >= sii->numcores)
    321 		return (NULL);
    322 
    323 	/*
    324 	 * If the user has provided an interrupt mask enabled function,
    325 	 * then assert interrupts are disabled before switching the core.
    326 	 */
    327 	ASSERT((sii->intrsenabled_fn == NULL) || !(*(sii)->intrsenabled_fn)((sii)->intr_arg));
    328 
    329 	switch (BUSTYPE(sih->bustype)) {
    330 	case SI_BUS:
    331 		/* map new one */
    332 		if (!sii->common_info->regs[coreidx]) {
    333 			sii->common_info->regs[coreidx] = REG_MAP(addr, SI_CORE_SIZE);
    334 			ASSERT(GOODREGS(sii->common_info->regs[coreidx]));
    335 		}
    336 		sii->curmap = regs = sii->common_info->regs[coreidx];
    337 		if (!sii->common_info->wrappers[coreidx]) {
    338 			sii->common_info->wrappers[coreidx] = REG_MAP(wrap, SI_CORE_SIZE);
    339 			ASSERT(GOODREGS(sii->common_info->wrappers[coreidx]));
    340 		}
    341 		sii->curwrap = sii->common_info->wrappers[coreidx];
    342 		break;
    343 
    344 
    345 	case SPI_BUS:
    346 	case SDIO_BUS:
    347 		sii->curmap = regs = (void *)((uintptr)addr);
    348 		sii->curwrap = (void *)((uintptr)wrap);
    349 		break;
    350 
    351 	case PCMCIA_BUS:
    352 	default:
    353 		ASSERT(0);
    354 		regs = NULL;
    355 		break;
    356 	}
    357 
    358 	sii->curmap = regs;
    359 	sii->curidx = coreidx;
    360 
    361 	return regs;
    362 }
    363 
    364 /* Return the number of address spaces in current core */
    365 int
    366 ai_numaddrspaces(si_t *sih)
    367 {
    368 	return 2;
    369 }
    370 
    371 /* Return the address of the nth address space in the current core */
    372 uint32
    373 ai_addrspace(si_t *sih, uint asidx)
    374 {
    375 	si_info_t *sii;
    376 	uint cidx;
    377 
    378 	sii = SI_INFO(sih);
    379 	cidx = sii->curidx;
    380 
    381 	if (asidx == 0)
    382 		return sii->common_info->coresba[cidx];
    383 	else if (asidx == 1)
    384 		return sii->common_info->coresba2[cidx];
    385 	else {
    386 		SI_ERROR(("%s: Need to parse the erom again to find addr space %d\n",
    387 		          __FUNCTION__, asidx));
    388 		return 0;
    389 	}
    390 }
    391 
    392 /* Return the size of the nth address space in the current core */
    393 uint32
    394 ai_addrspacesize(si_t *sih, uint asidx)
    395 {
    396 	si_info_t *sii;
    397 	uint cidx;
    398 
    399 	sii = SI_INFO(sih);
    400 	cidx = sii->curidx;
    401 
    402 	if (asidx == 0)
    403 		return sii->common_info->coresba_size[cidx];
    404 	else if (asidx == 1)
    405 		return sii->common_info->coresba2_size[cidx];
    406 	else {
    407 		SI_ERROR(("%s: Need to parse the erom again to find addr space %d\n",
    408 		          __FUNCTION__, asidx));
    409 		return 0;
    410 	}
    411 }
    412 
    413 uint
    414 ai_flag(si_t *sih)
    415 {
    416 	si_info_t *sii;
    417 	aidmp_t *ai;
    418 
    419 	sii = SI_INFO(sih);
    420 	ai = sii->curwrap;
    421 
    422 	return (R_REG(sii->osh, &ai->oobselouta30) & 0x1f);
    423 }
    424 
    425 void
    426 ai_setint(si_t *sih, int siflag)
    427 {
    428 }
    429 
    430 void
    431 ai_write_wrap_reg(si_t *sih, uint32 offset, uint32 val)
    432 {
    433 	si_info_t *sii = SI_INFO(sih);
    434 	aidmp_t *ai = sii->curwrap;
    435 	W_REG(sii->osh, (uint32 *)((uint8 *)ai+offset), val);
    436 	return;
    437 }
    438 
    439 uint
    440 ai_corevendor(si_t *sih)
    441 {
    442 	si_info_t *sii;
    443 	uint32 cia;
    444 
    445 	sii = SI_INFO(sih);
    446 	cia = sii->common_info->cia[sii->curidx];
    447 	return ((cia & CIA_MFG_MASK) >> CIA_MFG_SHIFT);
    448 }
    449 
    450 uint
    451 ai_corerev(si_t *sih)
    452 {
    453 	si_info_t *sii;
    454 	uint32 cib;
    455 
    456 	sii = SI_INFO(sih);
    457 	cib = sii->common_info->cib[sii->curidx];
    458 	return ((cib & CIB_REV_MASK) >> CIB_REV_SHIFT);
    459 }
    460 
    461 bool
    462 ai_iscoreup(si_t *sih)
    463 {
    464 	si_info_t *sii;
    465 	aidmp_t *ai;
    466 
    467 	sii = SI_INFO(sih);
    468 	ai = sii->curwrap;
    469 
    470 	return (((R_REG(sii->osh, &ai->ioctrl) & (SICF_FGC | SICF_CLOCK_EN)) == SICF_CLOCK_EN) &&
    471 	        ((R_REG(sii->osh, &ai->resetctrl) & AIRC_RESET) == 0));
    472 }
    473 
    474 /*
    475  * Switch to 'coreidx', issue a single arbitrary 32bit register mask&set operation,
    476  * switch back to the original core, and return the new value.
    477  *
    478  * When using the silicon backplane, no fidleing with interrupts or core switches are needed.
    479  *
    480  * Also, when using pci/pcie, we can optimize away the core switching for pci registers
    481  * and (on newer pci cores) chipcommon registers.
    482  */
    483 uint
    484 ai_corereg(si_t *sih, uint coreidx, uint regoff, uint mask, uint val)
    485 {
    486 	uint origidx = 0;
    487 	uint32 *r = NULL;
    488 	uint w;
    489 	uint intr_val = 0;
    490 	bool fast = FALSE;
    491 	si_info_t *sii;
    492 
    493 	sii = SI_INFO(sih);
    494 
    495 	ASSERT(GOODIDX(coreidx));
    496 	ASSERT(regoff < SI_CORE_SIZE);
    497 	ASSERT((val & ~mask) == 0);
    498 
    499 	if (coreidx >= SI_MAXCORES)
    500 		return 0;
    501 
    502 	if (BUSTYPE(sih->bustype) == SI_BUS) {
    503 		/* If internal bus, we can always get at everything */
    504 		fast = TRUE;
    505 		/* map if does not exist */
    506 		if (!sii->common_info->wrappers[coreidx]) {
    507 			sii->common_info->regs[coreidx] =
    508 			    REG_MAP(sii->common_info->coresba[coreidx], SI_CORE_SIZE);
    509 			ASSERT(GOODREGS(sii->common_info->regs[coreidx]));
    510 		}
    511 		r = (uint32 *)((uchar *)sii->common_info->regs[coreidx] + regoff);
    512 	} else if (BUSTYPE(sih->bustype) == PCI_BUS) {
    513 		/* If pci/pcie, we can get at pci/pcie regs and on newer cores to chipc */
    514 
    515 		if ((sii->common_info->coreid[coreidx] == CC_CORE_ID) && SI_FAST(sii)) {
    516 			/* Chipc registers are mapped at 12KB */
    517 
    518 			fast = TRUE;
    519 			r = (uint32 *)((char *)sii->curmap + PCI_16KB0_CCREGS_OFFSET + regoff);
    520 		} else if (sii->pub.buscoreidx == coreidx) {
    521 			/* pci registers are at either in the last 2KB of an 8KB window
    522 			 * or, in pcie and pci rev 13 at 8KB
    523 			 */
    524 			fast = TRUE;
    525 			if (SI_FAST(sii))
    526 				r = (uint32 *)((char *)sii->curmap +
    527 				               PCI_16KB0_PCIREGS_OFFSET + regoff);
    528 			else
    529 				r = (uint32 *)((char *)sii->curmap +
    530 				               ((regoff >= SBCONFIGOFF) ?
    531 				                PCI_BAR0_PCISBR_OFFSET : PCI_BAR0_PCIREGS_OFFSET) +
    532 				               regoff);
    533 		}
    534 	}
    535 
    536 	if (!fast) {
    537 		INTR_OFF(sii, intr_val);
    538 
    539 		/* save current core index */
    540 		origidx = si_coreidx(&sii->pub);
    541 
    542 		/* switch core */
    543 		r = (uint32*) ((uchar*) ai_setcoreidx(&sii->pub, coreidx) + regoff);
    544 	}
    545 	ASSERT(r != NULL);
    546 
    547 	/* mask and set */
    548 	if (mask || val) {
    549 		w = (R_REG(sii->osh, r) & ~mask) | val;
    550 		W_REG(sii->osh, r, w);
    551 	}
    552 
    553 	/* readback */
    554 	w = R_REG(sii->osh, r);
    555 
    556 	if (!fast) {
    557 		/* restore core index */
    558 		if (origidx != coreidx)
    559 			ai_setcoreidx(&sii->pub, origidx);
    560 
    561 		INTR_RESTORE(sii, intr_val);
    562 	}
    563 
    564 	return (w);
    565 }
    566 
    567 void
    568 ai_core_disable(si_t *sih, uint32 bits)
    569 {
    570 	si_info_t *sii;
    571 	volatile uint32 dummy;
    572 	aidmp_t *ai;
    573 
    574 	sii = SI_INFO(sih);
    575 
    576 	ASSERT(GOODREGS(sii->curwrap));
    577 	ai = sii->curwrap;
    578 
    579 	/* if core is already in reset, just return */
    580 	if (R_REG(sii->osh, &ai->resetctrl) & AIRC_RESET)
    581 		return;
    582 
    583 	W_REG(sii->osh, &ai->ioctrl, bits);
    584 	dummy = R_REG(sii->osh, &ai->ioctrl);
    585 	OSL_DELAY(10);
    586 
    587 	W_REG(sii->osh, &ai->resetctrl, AIRC_RESET);
    588 	OSL_DELAY(1);
    589 }
    590 
    591 /* reset and re-enable a core
    592  * inputs:
    593  * bits - core specific bits that are set during and after reset sequence
    594  * resetbits - core specific bits that are set only during reset sequence
    595  */
    596 void
    597 ai_core_reset(si_t *sih, uint32 bits, uint32 resetbits)
    598 {
    599 	si_info_t *sii;
    600 	aidmp_t *ai;
    601 	volatile uint32 dummy;
    602 
    603 	sii = SI_INFO(sih);
    604 	ASSERT(GOODREGS(sii->curwrap));
    605 	ai = sii->curwrap;
    606 
    607 	/*
    608 	 * Must do the disable sequence first to work for arbitrary current core state.
    609 	 */
    610 	ai_core_disable(sih, (bits | resetbits));
    611 
    612 	/*
    613 	 * Now do the initialization sequence.
    614 	 */
    615 	W_REG(sii->osh, &ai->ioctrl, (bits | SICF_FGC | SICF_CLOCK_EN));
    616 	dummy = R_REG(sii->osh, &ai->ioctrl);
    617 	W_REG(sii->osh, &ai->resetctrl, 0);
    618 	OSL_DELAY(1);
    619 
    620 	W_REG(sii->osh, &ai->ioctrl, (bits | SICF_CLOCK_EN));
    621 	dummy = R_REG(sii->osh, &ai->ioctrl);
    622 	OSL_DELAY(1);
    623 }
    624 
    625 
    626 void
    627 ai_core_cflags_wo(si_t *sih, uint32 mask, uint32 val)
    628 {
    629 	si_info_t *sii;
    630 	aidmp_t *ai;
    631 	uint32 w;
    632 
    633 	sii = SI_INFO(sih);
    634 	ASSERT(GOODREGS(sii->curwrap));
    635 	ai = sii->curwrap;
    636 
    637 	ASSERT((val & ~mask) == 0);
    638 
    639 	if (mask || val) {
    640 		w = ((R_REG(sii->osh, &ai->ioctrl) & ~mask) | val);
    641 		W_REG(sii->osh, &ai->ioctrl, w);
    642 	}
    643 }
    644 
    645 uint32
    646 ai_core_cflags(si_t *sih, uint32 mask, uint32 val)
    647 {
    648 	si_info_t *sii;
    649 	aidmp_t *ai;
    650 	uint32 w;
    651 
    652 	sii = SI_INFO(sih);
    653 	ASSERT(GOODREGS(sii->curwrap));
    654 	ai = sii->curwrap;
    655 
    656 	ASSERT((val & ~mask) == 0);
    657 
    658 	if (mask || val) {
    659 		w = ((R_REG(sii->osh, &ai->ioctrl) & ~mask) | val);
    660 		W_REG(sii->osh, &ai->ioctrl, w);
    661 	}
    662 
    663 	return R_REG(sii->osh, &ai->ioctrl);
    664 }
    665 
    666 uint32
    667 ai_core_sflags(si_t *sih, uint32 mask, uint32 val)
    668 {
    669 	si_info_t *sii;
    670 	aidmp_t *ai;
    671 	uint32 w;
    672 
    673 	sii = SI_INFO(sih);
    674 	ASSERT(GOODREGS(sii->curwrap));
    675 	ai = sii->curwrap;
    676 
    677 	ASSERT((val & ~mask) == 0);
    678 	ASSERT((mask & ~SISF_CORE_BITS) == 0);
    679 
    680 	if (mask || val) {
    681 		w = ((R_REG(sii->osh, &ai->iostatus) & ~mask) | val);
    682 		W_REG(sii->osh, &ai->iostatus, w);
    683 	}
    684 
    685 	return R_REG(sii->osh, &ai->iostatus);
    686 }
    687