1/*
2 * Misc utility routines for accessing chip-specific features
3 * of the SiliconBackplane-based Broadcom chips.
4 *
5 * Copyright (C) 2010, Broadcom Corporation. All Rights Reserved.
6 *
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
14 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
16 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
17 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 *
19 * $Id: aiutils.c,v 1.27.2.5 2011-01-26 18:24:11 Exp $
20 */
21
22#include <typedefs.h>
23#include <bcmdefs.h>
24#include <osl.h>
25#include <bcmutils.h>
26#include <siutils.h>
27#include <hndsoc.h>
28#include <sbchipc.h>
29#include <pcicfg.h>
30
31#include "siutils_priv.h"
32
33#include <bcmdevs.h>
34
35#define BCM47162_DMP() ((CHIPID(sih->chip) == BCM47162_CHIP_ID) && \
36	    (CHIPREV(sih->chiprev) == 0) && \
37	    (sii->coreid[sii->curidx] == MIPS74K_CORE_ID))
38
39#define BCM5357_DMP() (((CHIPID(sih->chip) == BCM5357_CHIP_ID) || \
40		(CHIPID(sih->chip) == BCM4749_CHIP_ID)) && \
41	    (sih->chippkg == BCM5357_PKG_ID) && \
42	    (sii->coreid[sii->curidx] == USB20H_CORE_ID))
43
44/* EROM parsing */
45
46static uint32
47get_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), *eromptr);
54		(*eromptr)++;
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_VMSG(("%s: Returning ent 0x%08x\n", __FUNCTION__, ent));
74	if (inv + nom) {
75		SI_VMSG(("  after %d invalid and %d non-matching entries\n", inv, nom));
76	}
77	return ent;
78}
79
80static uint32
81get_asd(si_t *sih, uint32 **eromptr, uint sp, uint ad, uint st, uint32 *addrl, uint32 *addrh,
82        uint32 *sizel, uint32 *sizeh)
83{
84	uint32 asd, sz, szd;
85
86	asd = get_erom_ent(sih, eromptr, ER_VALID, ER_VALID);
87	if (((asd & ER_TAG1) != ER_ADD) ||
88	    (((asd & AD_SP_MASK) >> AD_SP_SHIFT) != sp) ||
89	    ((asd & AD_ST_MASK) != st)) {
90		/* This is not what we want, "push" it back */
91		(*eromptr)--;
92		return 0;
93	}
94	*addrl = asd & AD_ADDR_MASK;
95	if (asd & AD_AG32)
96		*addrh = get_erom_ent(sih, eromptr, 0, 0);
97	else
98		*addrh = 0;
99	*sizeh = 0;
100	sz = asd & AD_SZ_MASK;
101	if (sz == AD_SZ_SZD) {
102		szd = get_erom_ent(sih, eromptr, 0, 0);
103		*sizel = szd & SD_SZ_MASK;
104		if (szd & SD_SG32)
105			*sizeh = get_erom_ent(sih, eromptr, 0, 0);
106	} else
107		*sizel = AD_SZ_BASE << (sz >> AD_SZ_SHIFT);
108
109	SI_VMSG(("  SP %d, ad %d: st = %d, 0x%08x_0x%08x @ 0x%08x_0x%08x\n",
110	        sp, ad, st, *sizeh, *sizel, *addrh, *addrl));
111
112	return asd;
113}
114
115static void
116ai_hwfixup(si_info_t *sii)
117{
118#ifdef	_CFE_
119	/* Fixup the interrupts in 4716 for i2s core so that ai_flag
120	 * works without having to look at the core sinking the
121	 * interrupt. We should have done this as the hardware default.
122	 *
123	 * Future chips should allocate interrupt lines in order (meaning
124	 * no line should be skipped), without regard for core index.
125	 */
126	if (BUSTYPE(sii->pub.bustype) == SI_BUS &&
127	    ((CHIPID(sii->pub.chip) == BCM4716_CHIP_ID) ||
128	     (CHIPID(sii->pub.chip) == BCM4748_CHIP_ID))) {
129		aidmp_t *i2s, *pcie, *cpu;
130
131		ASSERT(sii->coreid[3] == MIPS74K_CORE_ID);
132		cpu = REG_MAP(sii->wrapba[3], SI_CORE_SIZE);
133		ASSERT(sii->coreid[5] == PCIE_CORE_ID);
134		pcie = REG_MAP(sii->wrapba[5], SI_CORE_SIZE);
135		ASSERT(sii->coreid[8] == I2S_CORE_ID);
136		i2s = REG_MAP(sii->wrapba[8], SI_CORE_SIZE);
137		if ((R_REG(sii->osh, &cpu->oobselina74) != 0x08060504) ||
138		    (R_REG(sii->osh, &pcie->oobselina74) != 0x08060504) ||
139		    (R_REG(sii->osh, &i2s->oobselouta30) != 0x88)) {
140			SI_VMSG(("Unexpected oob values, not fixing i2s interrupt\n"));
141		} else {
142			/* Move i2s interrupt to oob line 7 instead of 8 */
143			W_REG(sii->osh, &cpu->oobselina74, 0x07060504);
144			W_REG(sii->osh, &pcie->oobselina74, 0x07060504);
145			W_REG(sii->osh, &i2s->oobselouta30, 0x87);
146			SI_VMSG(("Changed i2s interrupt to use oob line 7 instead of 8\n"));
147		}
148	}
149#endif	/* _CFE_ */
150}
151
152struct _corerev_entry {
153	uint corerev;
154	uint corerev_alias;
155};
156static struct _corerev_entry bcm4706_corerev_cc[] = {
157	{ 0x1f, CC_4706B0_CORE_REV },
158	{ 0, 0 }
159};
160static struct _corerev_entry bcm4706_corerev_socsram[] = {
161	{ 0x05, SOCRAM_4706B0_CORE_REV },
162	{ 0, 0 }
163};
164static struct _corerev_entry bcm4706_corerev_gmac[] = {
165	{ 0x00, GMAC_4706B0_CORE_REV },
166	{ 0, 0 }
167};
168
169struct _coreid_entry {
170	uint coreid;
171	uint coreid_alias;
172};
173static struct _coreid_entry bcm4706_coreid_table[] = {
174	{	CC_4706_CORE_ID, CC_CORE_ID },
175	{	SOCRAM_4706_CORE_ID, SOCRAM_CORE_ID },
176	{	GMAC_4706_CORE_ID, GMAC_CORE_ID },
177	{ 0, 0 }
178};
179
180static uint
181remap_coreid(si_t *sih, uint coreid)
182{
183	struct _coreid_entry *coreid_table = NULL;
184
185	if (CHIPID(sih->chip) == BCM4706_CHIP_ID)
186		coreid_table = &bcm4706_coreid_table[0];
187
188	if (coreid_table != NULL) {
189		uint i;
190
191		for (i = 0; coreid_table[i].coreid; i++)
192			if (coreid_table[i].coreid == coreid)
193				return coreid_table[i].coreid_alias;
194	}
195
196	return coreid;
197}
198
199static uint
200remap_corerev(si_t *sih, uint corerev)
201{
202	if (CHIPID(sih->chip) == BCM4706_CHIP_ID) {
203		si_info_t *sii = SI_INFO(sih);
204		uint i, coreid = sii->coreid[sii->curidx];
205		struct _corerev_entry *corerev_table = NULL;
206
207		if (coreid == CC_CORE_ID)
208			corerev_table = bcm4706_corerev_cc;
209		else if (coreid == GMAC_CORE_ID)
210			corerev_table = bcm4706_corerev_gmac;
211		else if (coreid == SOCRAM_CORE_ID)
212			corerev_table = bcm4706_corerev_socsram;
213		if (corerev_table != NULL) {
214			for (i = 0; corerev_table[i].corerev_alias; i++)
215				if (corerev_table[i].corerev == corerev)
216					return corerev_table[i].corerev_alias;
217		}
218	}
219
220	return corerev;
221}
222
223/* parse the enumeration rom to identify all cores */
224void
225BCMATTACHFN(ai_scan)(si_t *sih, void *regs, uint devid)
226{
227	si_info_t *sii = SI_INFO(sih);
228	chipcregs_t *cc = (chipcregs_t *)regs;
229	uint32 erombase, *eromptr, *eromlim;
230
231	erombase = R_REG(sii->osh, &cc->eromptr);
232
233	switch (BUSTYPE(sih->bustype)) {
234	case SI_BUS:
235		eromptr = (uint32 *)REG_MAP(erombase, SI_CORE_SIZE);
236		break;
237
238	case PCI_BUS:
239		/* Set wrappers address */
240		sii->curwrap = (void *)((uintptr)regs + SI_CORE_SIZE);
241
242		/* Now point the window at the erom */
243		OSL_PCI_WRITE_CONFIG(sii->osh, PCI_BAR0_WIN, 4, erombase);
244		eromptr = regs;
245		break;
246
247#ifdef BCMJTAG
248	case JTAG_BUS:
249		eromptr = (uint32 *)(uintptr)erombase;
250		break;
251#endif	/* BCMJTAG */
252
253	case PCMCIA_BUS:
254	default:
255		SI_ERROR(("Don't know how to do AXI enumertion on bus %d\n", sih->bustype));
256		ASSERT(0);
257		return;
258	}
259	eromlim = eromptr + (ER_REMAPCONTROL / sizeof(uint32));
260
261	SI_VMSG(("ai_scan: regs = 0x%p, erombase = 0x%08x, eromptr = 0x%p, eromlim = 0x%p\n",
262	         regs, erombase, eromptr, eromlim));
263	while (eromptr < eromlim) {
264		uint32 cia, cib, cid, mfg, crev, nmw, nsw, nmp, nsp;
265		uint32 mpd, asd, addrl, addrh, sizel, sizeh;
266		uint32 *base;
267		uint i, j, idx;
268		bool br;
269
270		br = FALSE;
271
272		/* Grok a component */
273		cia = get_erom_ent(sih, &eromptr, ER_TAG, ER_CI);
274		if (cia == (ER_END | ER_VALID)) {
275			SI_VMSG(("Found END of erom after %d cores\n", sii->numcores));
276			ai_hwfixup(sii);
277			return;
278		}
279		base = eromptr - 1;
280		cib = get_erom_ent(sih, &eromptr, 0, 0);
281
282		if ((cib & ER_TAG) != ER_CI) {
283			SI_ERROR(("CIA not followed by CIB\n"));
284			goto error;
285		}
286
287		cid = (cia & CIA_CID_MASK) >> CIA_CID_SHIFT;
288		mfg = (cia & CIA_MFG_MASK) >> CIA_MFG_SHIFT;
289		crev = (cib & CIB_REV_MASK) >> CIB_REV_SHIFT;
290		nmw = (cib & CIB_NMW_MASK) >> CIB_NMW_SHIFT;
291		nsw = (cib & CIB_NSW_MASK) >> CIB_NSW_SHIFT;
292		nmp = (cib & CIB_NMP_MASK) >> CIB_NMP_SHIFT;
293		nsp = (cib & CIB_NSP_MASK) >> CIB_NSP_SHIFT;
294
295		SI_VMSG(("Found component 0x%04x/0x%04x rev %d at erom addr 0x%p, with nmw = %d, "
296		         "nsw = %d, nmp = %d & nsp = %d\n",
297		         mfg, cid, crev, base, nmw, nsw, nmp, nsp));
298
299		if (((mfg == MFGID_ARM) && (cid == DEF_AI_COMP)) || (nsp == 0))
300			continue;
301		if ((nmw + nsw == 0)) {
302			/* A component which is not a core */
303			if (cid == OOB_ROUTER_CORE_ID) {
304				asd = get_asd(sih, &eromptr, 0, 0, AD_ST_SLAVE,
305					&addrl, &addrh, &sizel, &sizeh);
306				if (asd != 0) {
307					sii->oob_router = addrl;
308				}
309			}
310			if (cid != GMAC_COMMON_4706_CORE_ID)
311				continue;
312		}
313
314		idx = sii->numcores;
315/*		sii->eromptr[idx] = base; */
316		sii->cia[idx] = cia;
317		sii->cib[idx] = cib;
318		sii->coreid[idx] = remap_coreid(sih, cid);
319
320		for (i = 0; i < nmp; i++) {
321			mpd = get_erom_ent(sih, &eromptr, ER_VALID, ER_VALID);
322			if ((mpd & ER_TAG) != ER_MP) {
323				SI_ERROR(("Not enough MP entries for component 0x%x\n", cid));
324				goto error;
325			}
326			SI_VMSG(("  Master port %d, mp: %d id: %d\n", i,
327			         (mpd & MPD_MP_MASK) >> MPD_MP_SHIFT,
328			         (mpd & MPD_MUI_MASK) >> MPD_MUI_SHIFT));
329		}
330
331		/* First Slave Address Descriptor should be port 0:
332		 * the main register space for the core
333		 */
334		asd = get_asd(sih, &eromptr, 0, 0, AD_ST_SLAVE, &addrl, &addrh, &sizel, &sizeh);
335		if (asd == 0) {
336			/* Try again to see if it is a bridge */
337			asd = get_asd(sih, &eromptr, 0, 0, AD_ST_BRIDGE, &addrl, &addrh,
338			              &sizel, &sizeh);
339			if (asd != 0)
340				br = TRUE;
341			else
342				if ((addrh != 0) || (sizeh != 0) || (sizel != SI_CORE_SIZE)) {
343					SI_ERROR(("First Slave ASD for core 0x%04x malformed "
344					          "(0x%08x)\n", cid, asd));
345					goto error;
346				}
347		}
348		sii->coresba[idx] = addrl;
349		sii->coresba_size[idx] = sizel;
350		/* Get any more ASDs in port 0 */
351		j = 1;
352		do {
353			asd = get_asd(sih, &eromptr, 0, j, AD_ST_SLAVE, &addrl, &addrh,
354			              &sizel, &sizeh);
355			if ((asd != 0) && (j == 1) && (sizel == SI_CORE_SIZE)) {
356				sii->coresba2[idx] = addrl;
357				sii->coresba2_size[idx] = sizel;
358			}
359			j++;
360		} while (asd != 0);
361
362		/* Go through the ASDs for other slave ports */
363		for (i = 1; i < nsp; i++) {
364			j = 0;
365			do {
366				asd = get_asd(sih, &eromptr, i, j++, AD_ST_SLAVE, &addrl, &addrh,
367				              &sizel, &sizeh);
368			} while (asd != 0);
369			if (j == 0) {
370				SI_ERROR((" SP %d has no address descriptors\n", i));
371				goto error;
372			}
373		}
374
375		/* Now get master wrappers */
376		for (i = 0; i < nmw; i++) {
377			asd = get_asd(sih, &eromptr, i, 0, AD_ST_MWRAP, &addrl, &addrh,
378			              &sizel, &sizeh);
379			if (asd == 0) {
380				SI_ERROR(("Missing descriptor for MW %d\n", i));
381				goto error;
382			}
383			if ((sizeh != 0) || (sizel != SI_CORE_SIZE)) {
384				SI_ERROR(("Master wrapper %d is not 4KB\n", i));
385				goto error;
386			}
387			if (i == 0)
388				sii->wrapba[idx] = addrl;
389		}
390
391		/* And finally slave wrappers */
392		for (i = 0; i < nsw; i++) {
393			uint fwp = (nsp == 1) ? 0 : 1;
394			asd = get_asd(sih, &eromptr, fwp + i, 0, AD_ST_SWRAP, &addrl, &addrh,
395			              &sizel, &sizeh);
396			if (asd == 0) {
397				SI_ERROR(("Missing descriptor for SW %d\n", i));
398				goto error;
399			}
400			if ((sizeh != 0) || (sizel != SI_CORE_SIZE)) {
401				SI_ERROR(("Slave wrapper %d is not 4KB\n", i));
402				goto error;
403			}
404			if ((nmw == 0) && (i == 0))
405				sii->wrapba[idx] = addrl;
406		}
407
408		/* Don't record bridges */
409		if (br)
410			continue;
411
412		/* Done with core */
413		sii->numcores++;
414	}
415
416	SI_ERROR(("Reached end of erom without finding END"));
417
418error:
419	sii->numcores = 0;
420	return;
421}
422
423/* This function changes the logical "focus" to the indicated core.
424 * Return the current core's virtual address.
425 */
426void *
427ai_setcoreidx(si_t *sih, uint coreidx)
428{
429	si_info_t *sii = SI_INFO(sih);
430	uint32 addr = sii->coresba[coreidx];
431	uint32 wrap = sii->wrapba[coreidx];
432	void *regs;
433
434	if (coreidx >= sii->numcores)
435		return (NULL);
436
437	/*
438	 * If the user has provided an interrupt mask enabled function,
439	 * then assert interrupts are disabled before switching the core.
440	 */
441	ASSERT((sii->intrsenabled_fn == NULL) || !(*(sii)->intrsenabled_fn)((sii)->intr_arg));
442
443	switch (BUSTYPE(sih->bustype)) {
444	case SI_BUS:
445		/* map new one */
446		if (!sii->regs[coreidx]) {
447			sii->regs[coreidx] = REG_MAP(addr, SI_CORE_SIZE);
448			ASSERT(GOODREGS(sii->regs[coreidx]));
449		}
450		sii->curmap = regs = sii->regs[coreidx];
451		if (!sii->wrappers[coreidx]) {
452			sii->wrappers[coreidx] = REG_MAP(wrap, SI_CORE_SIZE);
453			ASSERT(GOODREGS(sii->wrappers[coreidx]));
454		}
455		sii->curwrap = sii->wrappers[coreidx];
456		break;
457
458	case PCI_BUS:
459		/* point bar0 window */
460		OSL_PCI_WRITE_CONFIG(sii->osh, PCI_BAR0_WIN, 4, addr);
461		regs = sii->curmap;
462		/* point bar0 2nd 4KB window */
463		OSL_PCI_WRITE_CONFIG(sii->osh, PCI_BAR0_WIN2, 4, wrap);
464		break;
465
466#ifdef BCMJTAG
467	case JTAG_BUS:
468		sii->curmap = regs = (void *)((uintptr)addr);
469		sii->curwrap = (void *)((uintptr)wrap);
470		break;
471#endif	/* BCMJTAG */
472
473	case PCMCIA_BUS:
474	default:
475		ASSERT(0);
476		regs = NULL;
477		break;
478	}
479
480	sii->curmap = regs;
481	sii->curidx = coreidx;
482
483	return regs;
484}
485
486/* Return the number of address spaces in current core */
487int
488ai_numaddrspaces(si_t *sih)
489{
490	return 2;
491}
492
493/* Return the address of the nth address space in the current core */
494uint32
495ai_addrspace(si_t *sih, uint asidx)
496{
497	si_info_t *sii;
498	uint cidx;
499
500	sii = SI_INFO(sih);
501	cidx = sii->curidx;
502
503	if (asidx == 0)
504		return sii->coresba[cidx];
505	else if (asidx == 1)
506		return sii->coresba2[cidx];
507	else {
508		SI_ERROR(("%s: Need to parse the erom again to find addr space %d\n",
509		          __FUNCTION__, asidx));
510		return 0;
511	}
512}
513
514/* Return the size of the nth address space in the current core */
515uint32
516ai_addrspacesize(si_t *sih, uint asidx)
517{
518	si_info_t *sii;
519	uint cidx;
520
521	sii = SI_INFO(sih);
522	cidx = sii->curidx;
523
524	if (asidx == 0)
525		return sii->coresba_size[cidx];
526	else if (asidx == 1)
527		return sii->coresba2_size[cidx];
528	else {
529		SI_ERROR(("%s: Need to parse the erom again to find addr space %d\n",
530		          __FUNCTION__, asidx));
531		return 0;
532	}
533}
534
535uint
536ai_flag(si_t *sih)
537{
538	si_info_t *sii;
539	aidmp_t *ai;
540
541	sii = SI_INFO(sih);
542	if (BCM47162_DMP()) {
543		SI_ERROR(("%s: Attempting to read MIPS DMP registers on 47162a0", __FUNCTION__));
544		return sii->curidx;
545	}
546	if (BCM5357_DMP()) {
547		SI_ERROR(("%s: Attempting to read USB20H DMP registers on 5357b0\n", __FUNCTION__));
548		return sii->curidx;
549	}
550	ai = sii->curwrap;
551
552	return (R_REG(sii->osh, &ai->oobselouta30) & 0x1f);
553}
554
555void
556ai_setint(si_t *sih, int siflag)
557{
558}
559
560void
561ai_write_wrap_reg(si_t *sih, uint32 offset, uint32 val)
562{
563	si_info_t *sii = SI_INFO(sih);
564	uint32 *w = (uint32 *) sii->curwrap;
565	W_REG(sii->osh, w+(offset/4), val);
566	return;
567}
568
569uint
570ai_corevendor(si_t *sih)
571{
572	si_info_t *sii;
573	uint32 cia;
574
575	sii = SI_INFO(sih);
576	cia = sii->cia[sii->curidx];
577	return ((cia & CIA_MFG_MASK) >> CIA_MFG_SHIFT);
578}
579
580uint
581ai_corerev(si_t *sih)
582{
583	si_info_t *sii;
584	uint32 cib;
585
586	sii = SI_INFO(sih);
587	cib = sii->cib[sii->curidx];
588	return remap_corerev(sih, (cib & CIB_REV_MASK) >> CIB_REV_SHIFT);
589}
590
591bool
592ai_iscoreup(si_t *sih)
593{
594	si_info_t *sii;
595	aidmp_t *ai;
596
597	sii = SI_INFO(sih);
598	ai = sii->curwrap;
599
600	return (((R_REG(sii->osh, &ai->ioctrl) & (SICF_FGC | SICF_CLOCK_EN)) == SICF_CLOCK_EN) &&
601	        ((R_REG(sii->osh, &ai->resetctrl) & AIRC_RESET) == 0));
602}
603
604/*
605 * Switch to 'coreidx', issue a single arbitrary 32bit register mask&set operation,
606 * switch back to the original core, and return the new value.
607 *
608 * When using the silicon backplane, no fiddling with interrupts or core switches is needed.
609 *
610 * Also, when using pci/pcie, we can optimize away the core switching for pci registers
611 * and (on newer pci cores) chipcommon registers.
612 */
613uint
614ai_corereg(si_t *sih, uint coreidx, uint regoff, uint mask, uint val)
615{
616	uint origidx = 0;
617	uint32 *r = NULL;
618	uint w;
619	uint intr_val = 0;
620	bool fast = FALSE;
621	si_info_t *sii;
622
623	sii = SI_INFO(sih);
624
625	ASSERT(GOODIDX(coreidx));
626	ASSERT(regoff < SI_CORE_SIZE);
627	ASSERT((val & ~mask) == 0);
628
629	if (coreidx >= SI_MAXCORES)
630		return 0;
631
632	if (BUSTYPE(sih->bustype) == SI_BUS) {
633		/* If internal bus, we can always get at everything */
634		fast = TRUE;
635		/* map if does not exist */
636		if (!sii->regs[coreidx]) {
637			sii->regs[coreidx] = REG_MAP(sii->coresba[coreidx],
638			                            SI_CORE_SIZE);
639			ASSERT(GOODREGS(sii->regs[coreidx]));
640		}
641		r = (uint32 *)((uchar *)sii->regs[coreidx] + regoff);
642	} else if (BUSTYPE(sih->bustype) == PCI_BUS) {
643		/* If pci/pcie, we can get at pci/pcie regs and on newer cores to chipc */
644
645		if ((sii->coreid[coreidx] == CC_CORE_ID) && SI_FAST(sii)) {
646			/* Chipc registers are mapped at 12KB */
647
648			fast = TRUE;
649			r = (uint32 *)((char *)sii->curmap + PCI_16KB0_CCREGS_OFFSET + regoff);
650		} else if (sii->pub.buscoreidx == coreidx) {
651			/* pci registers are at either in the last 2KB of an 8KB window
652			 * or, in pcie and pci rev 13 at 8KB
653			 */
654			fast = TRUE;
655			if (SI_FAST(sii))
656				r = (uint32 *)((char *)sii->curmap +
657				               PCI_16KB0_PCIREGS_OFFSET + regoff);
658			else
659				r = (uint32 *)((char *)sii->curmap +
660				               ((regoff >= SBCONFIGOFF) ?
661				                PCI_BAR0_PCISBR_OFFSET : PCI_BAR0_PCIREGS_OFFSET) +
662				               regoff);
663		}
664	}
665
666	if (!fast) {
667		INTR_OFF(sii, intr_val);
668
669		/* save current core index */
670		origidx = si_coreidx(&sii->pub);
671
672		/* switch core */
673		r = (uint32*) ((uchar*) ai_setcoreidx(&sii->pub, coreidx) + regoff);
674	}
675	ASSERT(r != NULL);
676
677	/* mask and set */
678	if (mask || val) {
679		w = (R_REG(sii->osh, r) & ~mask) | val;
680		W_REG(sii->osh, r, w);
681	}
682
683	/* readback */
684	w = R_REG(sii->osh, r);
685
686	if (!fast) {
687		/* restore core index */
688		if (origidx != coreidx)
689			ai_setcoreidx(&sii->pub, origidx);
690
691		INTR_RESTORE(sii, intr_val);
692	}
693
694	return (w);
695}
696
697void
698ai_core_disable(si_t *sih, uint32 bits)
699{
700	si_info_t *sii;
701	volatile uint32 dummy;
702	aidmp_t *ai;
703
704	sii = SI_INFO(sih);
705
706	ASSERT(GOODREGS(sii->curwrap));
707	ai = sii->curwrap;
708
709	/* if core is already in reset, just return */
710	if (R_REG(sii->osh, &ai->resetctrl) & AIRC_RESET)
711		return;
712
713	W_REG(sii->osh, &ai->ioctrl, bits);
714	dummy = R_REG(sii->osh, &ai->ioctrl);
715	OSL_DELAY(10);
716
717	W_REG(sii->osh, &ai->resetctrl, AIRC_RESET);
718	dummy = R_REG(sii->osh, &ai->resetctrl);
719	OSL_DELAY(1);
720}
721
722/* reset and re-enable a core
723 * inputs:
724 * bits - core specific bits that are set during and after reset sequence
725 * resetbits - core specific bits that are set only during reset sequence
726 */
727void
728ai_core_reset(si_t *sih, uint32 bits, uint32 resetbits)
729{
730	si_info_t *sii;
731	aidmp_t *ai;
732	volatile uint32 dummy;
733
734	sii = SI_INFO(sih);
735	ASSERT(GOODREGS(sii->curwrap));
736	ai = sii->curwrap;
737
738	/*
739	 * Must do the disable sequence first to work for arbitrary current core state.
740	 */
741	ai_core_disable(sih, (bits | resetbits));
742
743	/*
744	 * Now do the initialization sequence.
745	 */
746	W_REG(sii->osh, &ai->ioctrl, (bits | SICF_FGC | SICF_CLOCK_EN));
747	dummy = R_REG(sii->osh, &ai->ioctrl);
748	W_REG(sii->osh, &ai->resetctrl, 0);
749	OSL_DELAY(1);
750
751	W_REG(sii->osh, &ai->ioctrl, (bits | SICF_CLOCK_EN));
752	dummy = R_REG(sii->osh, &ai->ioctrl);
753	OSL_DELAY(1);
754}
755
756
757void
758ai_core_cflags_wo(si_t *sih, uint32 mask, uint32 val)
759{
760	si_info_t *sii;
761	aidmp_t *ai;
762	uint32 w;
763
764	sii = SI_INFO(sih);
765
766	if (BCM47162_DMP()) {
767		SI_ERROR(("%s: Accessing MIPS DMP register (ioctrl) on 47162a0",
768		          __FUNCTION__));
769		return;
770	}
771	if (BCM5357_DMP()) {
772		SI_ERROR(("%s: Accessing USB20H DMP register (ioctrl) on 5357\n",
773		          __FUNCTION__));
774		return;
775	}
776
777	ASSERT(GOODREGS(sii->curwrap));
778	ai = sii->curwrap;
779
780	ASSERT((val & ~mask) == 0);
781
782	if (mask || val) {
783		w = ((R_REG(sii->osh, &ai->ioctrl) & ~mask) | val);
784		W_REG(sii->osh, &ai->ioctrl, w);
785	}
786}
787
788uint32
789ai_core_cflags(si_t *sih, uint32 mask, uint32 val)
790{
791	si_info_t *sii;
792	aidmp_t *ai;
793	uint32 w;
794
795	sii = SI_INFO(sih);
796	if (BCM47162_DMP()) {
797		SI_ERROR(("%s: Accessing MIPS DMP register (ioctrl) on 47162a0",
798		          __FUNCTION__));
799		return 0;
800	}
801	if (BCM5357_DMP()) {
802		SI_ERROR(("%s: Accessing USB20H DMP register (ioctrl) on 5357\n",
803		          __FUNCTION__));
804		return 0;
805	}
806
807	ASSERT(GOODREGS(sii->curwrap));
808	ai = sii->curwrap;
809
810	ASSERT((val & ~mask) == 0);
811
812	if (mask || val) {
813		w = ((R_REG(sii->osh, &ai->ioctrl) & ~mask) | val);
814		W_REG(sii->osh, &ai->ioctrl, w);
815	}
816
817	return R_REG(sii->osh, &ai->ioctrl);
818}
819
820uint32
821ai_core_sflags(si_t *sih, uint32 mask, uint32 val)
822{
823	si_info_t *sii;
824	aidmp_t *ai;
825	uint32 w;
826
827	sii = SI_INFO(sih);
828	if (BCM47162_DMP()) {
829		SI_ERROR(("%s: Accessing MIPS DMP register (iostatus) on 47162a0",
830		          __FUNCTION__));
831		return 0;
832	}
833	if (BCM5357_DMP()) {
834		SI_ERROR(("%s: Accessing USB20H DMP register (iostatus) on 5357\n",
835		          __FUNCTION__));
836		return 0;
837	}
838
839	ASSERT(GOODREGS(sii->curwrap));
840	ai = sii->curwrap;
841
842	ASSERT((val & ~mask) == 0);
843	ASSERT((mask & ~SISF_CORE_BITS) == 0);
844
845	if (mask || val) {
846		w = ((R_REG(sii->osh, &ai->iostatus) & ~mask) | val);
847		W_REG(sii->osh, &ai->iostatus, w);
848	}
849
850	return R_REG(sii->osh, &ai->iostatus);
851}
852
853#if defined(BCMDBG_DUMP)
854/* print interesting aidmp registers */
855void
856ai_dumpregs(si_t *sih, struct bcmstrbuf *b)
857{
858	si_info_t *sii;
859	osl_t *osh;
860	aidmp_t *ai;
861	uint i;
862
863	sii = SI_INFO(sih);
864	osh = sii->osh;
865
866	for (i = 0; i < sii->numcores; i++) {
867		si_setcoreidx(&sii->pub, i);
868		ai = sii->curwrap;
869
870		bcm_bprintf(b, "core 0x%x: \n", sii->coreid[i]);
871		if (BCM47162_DMP()) {
872			bcm_bprintf(b, "Skipping mips74k in 47162a0\n");
873			continue;
874		}
875		if (BCM5357_DMP()) {
876			bcm_bprintf(b, "Skipping usb20h in 5357\n");
877			continue;
878		}
879
880		bcm_bprintf(b, "ioctrlset 0x%x ioctrlclear 0x%x ioctrl 0x%x iostatus 0x%x"
881			    "ioctrlwidth 0x%x iostatuswidth 0x%x\n"
882			    "resetctrl 0x%x resetstatus 0x%x resetreadid 0x%x resetwriteid 0x%x\n"
883			    "errlogctrl 0x%x errlogdone 0x%x errlogstatus 0x%x"
884			    "errlogaddrlo 0x%x errlogaddrhi 0x%x\n"
885			    "errlogid 0x%x errloguser 0x%x errlogflags 0x%x\n"
886			    "intstatus 0x%x config 0x%x itcr 0x%x\n",
887			    R_REG(osh, &ai->ioctrlset),
888			    R_REG(osh, &ai->ioctrlclear),
889			    R_REG(osh, &ai->ioctrl),
890			    R_REG(osh, &ai->iostatus),
891			    R_REG(osh, &ai->ioctrlwidth),
892			    R_REG(osh, &ai->iostatuswidth),
893			    R_REG(osh, &ai->resetctrl),
894			    R_REG(osh, &ai->resetstatus),
895			    R_REG(osh, &ai->resetreadid),
896			    R_REG(osh, &ai->resetwriteid),
897			    R_REG(osh, &ai->errlogctrl),
898			    R_REG(osh, &ai->errlogdone),
899			    R_REG(osh, &ai->errlogstatus),
900			    R_REG(osh, &ai->errlogaddrlo),
901			    R_REG(osh, &ai->errlogaddrhi),
902			    R_REG(osh, &ai->errlogid),
903			    R_REG(osh, &ai->errloguser),
904			    R_REG(osh, &ai->errlogflags),
905			    R_REG(osh, &ai->intstatus),
906			    R_REG(osh, &ai->config),
907			    R_REG(osh, &ai->itcr));
908		if ((sih->chip == BCM4331_CHIP_ID) && (sii->coreid[i] == PCIE_CORE_ID)) {
909			/* point bar0 2nd 4KB window */
910			OSL_PCI_WRITE_CONFIG(sii->osh, PCI_BAR0_WIN2, 4, 0x18103000);
911			bcm_bprintf(b, "ioctrlset 0x%x ioctrlclear 0x%x ioctrl 0x%x iostatus 0x%x"
912				    "ioctrlwidth 0x%x iostatuswidth 0x%x\n"
913				    "resetctrl 0x%x resetstatus 0x%x resetreadid 0x%x"
914				    " resetwriteid 0x%x\n"
915				    "errlogctrl 0x%x errlogdone 0x%x errlogstatus 0x%x"
916				    "errlogaddrlo 0x%x errlogaddrhi 0x%x\n"
917				    "errlogid 0x%x errloguser 0x%x errlogflags 0x%x\n"
918				    "intstatus 0x%x config 0x%x itcr 0x%x\n",
919				    R_REG(osh, &ai->ioctrlset),
920				    R_REG(osh, &ai->ioctrlclear),
921				    R_REG(osh, &ai->ioctrl),
922				    R_REG(osh, &ai->iostatus),
923				    R_REG(osh, &ai->ioctrlwidth),
924				    R_REG(osh, &ai->iostatuswidth),
925				    R_REG(osh, &ai->resetctrl),
926				    R_REG(osh, &ai->resetstatus),
927				    R_REG(osh, &ai->resetreadid),
928				    R_REG(osh, &ai->resetwriteid),
929				    R_REG(osh, &ai->errlogctrl),
930				    R_REG(osh, &ai->errlogdone),
931				    R_REG(osh, &ai->errlogstatus),
932				    R_REG(osh, &ai->errlogaddrlo),
933				    R_REG(osh, &ai->errlogaddrhi),
934				    R_REG(osh, &ai->errlogid),
935				    R_REG(osh, &ai->errloguser),
936				    R_REG(osh, &ai->errlogflags),
937				    R_REG(osh, &ai->intstatus),
938				    R_REG(osh, &ai->config),
939				    R_REG(osh, &ai->itcr));
940			/* bar0 2nd 4KB window will be fixed in the next setcore */
941		}
942	}
943}
944#endif
945