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: sbutils.c,v 1.662.4.10.2.7.4.2 2010/04/19 05:48:48 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 <bcmdevs.h>
34#include <hndsoc.h>
35#include <sbchipc.h>
36#include <pcicfg.h>
37#include <sbpcmcia.h>
38
39#include "siutils_priv.h"
40
41/* local prototypes */
42static uint _sb_coreidx(si_info_t *sii, uint32 sba);
43static uint _sb_scan(si_info_t *sii, uint32 sba, void *regs, uint bus, uint32 sbba,
44                     uint ncores);
45static uint32 _sb_coresba(si_info_t *sii);
46static void *_sb_setcoreidx(si_info_t *sii, uint coreidx);
47
48#define	SET_SBREG(sii, r, mask, val)	\
49		W_SBREG((sii), (r), ((R_SBREG((sii), (r)) & ~(mask)) | (val)))
50#define	REGS2SB(va)	(sbconfig_t*) ((int8*)(va) + SBCONFIGOFF)
51
52/* sonicsrev */
53#define	SONICS_2_2	(SBIDL_RV_2_2 >> SBIDL_RV_SHIFT)
54#define	SONICS_2_3	(SBIDL_RV_2_3 >> SBIDL_RV_SHIFT)
55
56#define	R_SBREG(sii, sbr)	sb_read_sbreg((sii), (sbr))
57#define	W_SBREG(sii, sbr, v)	sb_write_sbreg((sii), (sbr), (v))
58#define	AND_SBREG(sii, sbr, v)	W_SBREG((sii), (sbr), (R_SBREG((sii), (sbr)) & (v)))
59#define	OR_SBREG(sii, sbr, v)	W_SBREG((sii), (sbr), (R_SBREG((sii), (sbr)) | (v)))
60
61static uint32
62sb_read_sbreg(si_info_t *sii, volatile uint32 *sbr)
63{
64	uint8 tmp;
65	uint32 val, intr_val = 0;
66
67
68	/*
69	 * compact flash only has 11 bits address, while we needs 12 bits address.
70	 * MEM_SEG will be OR'd with other 11 bits address in hardware,
71	 * so we program MEM_SEG with 12th bit when necessary(access sb regsiters).
72	 * For normal PCMCIA bus(CFTable_regwinsz > 2k), do nothing special
73	 */
74	if (PCMCIA(sii)) {
75		INTR_OFF(sii, intr_val);
76		tmp = 1;
77		OSL_PCMCIA_WRITE_ATTR(sii->osh, MEM_SEG, &tmp, 1);
78		sbr = (volatile uint32 *)((uintptr)sbr & ~(1 << 11)); /* mask out bit 11 */
79	}
80
81	val = R_REG(sii->osh, sbr);
82
83	if (PCMCIA(sii)) {
84		tmp = 0;
85		OSL_PCMCIA_WRITE_ATTR(sii->osh, MEM_SEG, &tmp, 1);
86		INTR_RESTORE(sii, intr_val);
87	}
88
89	return (val);
90}
91
92static void
93sb_write_sbreg(si_info_t *sii, volatile uint32 *sbr, uint32 v)
94{
95	uint8 tmp;
96	volatile uint32 dummy;
97	uint32 intr_val = 0;
98
99
100	/*
101	 * compact flash only has 11 bits address, while we needs 12 bits address.
102	 * MEM_SEG will be OR'd with other 11 bits address in hardware,
103	 * so we program MEM_SEG with 12th bit when necessary(access sb regsiters).
104	 * For normal PCMCIA bus(CFTable_regwinsz > 2k), do nothing special
105	 */
106	if (PCMCIA(sii)) {
107		INTR_OFF(sii, intr_val);
108		tmp = 1;
109		OSL_PCMCIA_WRITE_ATTR(sii->osh, MEM_SEG, &tmp, 1);
110		sbr = (volatile uint32 *)((uintptr)sbr & ~(1 << 11)); /* mask out bit 11 */
111	}
112
113	if (BUSTYPE(sii->pub.bustype) == PCMCIA_BUS) {
114#ifdef IL_BIGENDIAN
115		dummy = R_REG(sii->osh, sbr);
116		W_REG(sii->osh, ((volatile uint16 *)sbr + 1), (uint16)((v >> 16) & 0xffff));
117		dummy = R_REG(sii->osh, sbr);
118		W_REG(sii->osh, (volatile uint16 *)sbr, (uint16)(v & 0xffff));
119#else
120		dummy = R_REG(sii->osh, sbr);
121		W_REG(sii->osh, (volatile uint16 *)sbr, (uint16)(v & 0xffff));
122		dummy = R_REG(sii->osh, sbr);
123		W_REG(sii->osh, ((volatile uint16 *)sbr + 1), (uint16)((v >> 16) & 0xffff));
124#endif	/* IL_BIGENDIAN */
125	} else
126		W_REG(sii->osh, sbr, v);
127
128	if (PCMCIA(sii)) {
129		tmp = 0;
130		OSL_PCMCIA_WRITE_ATTR(sii->osh, MEM_SEG, &tmp, 1);
131		INTR_RESTORE(sii, intr_val);
132	}
133}
134
135uint
136sb_coreid(si_t *sih)
137{
138	si_info_t *sii;
139	sbconfig_t *sb;
140
141	sii = SI_INFO(sih);
142	sb = REGS2SB(sii->curmap);
143
144	return ((R_SBREG(sii, &sb->sbidhigh) & SBIDH_CC_MASK) >> SBIDH_CC_SHIFT);
145}
146
147uint
148sb_flag(si_t *sih)
149{
150	si_info_t *sii;
151	sbconfig_t *sb;
152
153	sii = SI_INFO(sih);
154	sb = REGS2SB(sii->curmap);
155
156	return R_SBREG(sii, &sb->sbtpsflag) & SBTPS_NUM0_MASK;
157}
158
159void
160sb_setint(si_t *sih, int siflag)
161{
162	si_info_t *sii;
163	sbconfig_t *sb;
164	uint32 vec;
165
166	sii = SI_INFO(sih);
167	sb = REGS2SB(sii->curmap);
168
169	if (siflag == -1)
170		vec = 0;
171	else
172		vec = 1 << siflag;
173	W_SBREG(sii, &sb->sbintvec, vec);
174}
175
176/* return core index of the core with address 'sba' */
177static uint
178_sb_coreidx(si_info_t *sii, uint32 sba)
179{
180	uint i;
181
182	for (i = 0; i < sii->numcores; i ++)
183		if (sba == sii->common_info->coresba[i])
184			return i;
185	return BADIDX;
186}
187
188/* return core address of the current core */
189static uint32
190_sb_coresba(si_info_t *sii)
191{
192	uint32 sbaddr;
193
194
195	switch (BUSTYPE(sii->pub.bustype)) {
196	case SI_BUS: {
197		sbconfig_t *sb = REGS2SB(sii->curmap);
198		sbaddr = sb_base(R_SBREG(sii, &sb->sbadmatch0));
199		break;
200	}
201
202	case PCI_BUS:
203		sbaddr = OSL_PCI_READ_CONFIG(sii->osh, PCI_BAR0_WIN, sizeof(uint32));
204		break;
205
206	case PCMCIA_BUS: {
207		uint8 tmp = 0;
208		OSL_PCMCIA_READ_ATTR(sii->osh, PCMCIA_ADDR0, &tmp, 1);
209		sbaddr  = (uint32)tmp << 12;
210		OSL_PCMCIA_READ_ATTR(sii->osh, PCMCIA_ADDR1, &tmp, 1);
211		sbaddr |= (uint32)tmp << 16;
212		OSL_PCMCIA_READ_ATTR(sii->osh, PCMCIA_ADDR2, &tmp, 1);
213		sbaddr |= (uint32)tmp << 24;
214		break;
215	}
216
217	case SPI_BUS:
218	case SDIO_BUS:
219		sbaddr = (uint32)(uintptr)sii->curmap;
220		break;
221
222
223	default:
224		sbaddr = BADCOREADDR;
225		break;
226	}
227
228	return sbaddr;
229}
230
231uint
232sb_corevendor(si_t *sih)
233{
234	si_info_t *sii;
235	sbconfig_t *sb;
236
237	sii = SI_INFO(sih);
238	sb = REGS2SB(sii->curmap);
239
240	return ((R_SBREG(sii, &sb->sbidhigh) & SBIDH_VC_MASK) >> SBIDH_VC_SHIFT);
241}
242
243uint
244sb_corerev(si_t *sih)
245{
246	si_info_t *sii;
247	sbconfig_t *sb;
248	uint sbidh;
249
250	sii = SI_INFO(sih);
251	sb = REGS2SB(sii->curmap);
252	sbidh = R_SBREG(sii, &sb->sbidhigh);
253
254	return (SBCOREREV(sbidh));
255}
256
257/* set core-specific control flags */
258void
259sb_core_cflags_wo(si_t *sih, uint32 mask, uint32 val)
260{
261	si_info_t *sii;
262	sbconfig_t *sb;
263	uint32 w;
264
265	sii = SI_INFO(sih);
266	sb = REGS2SB(sii->curmap);
267
268	ASSERT((val & ~mask) == 0);
269
270	/* mask and set */
271	w = (R_SBREG(sii, &sb->sbtmstatelow) & ~(mask << SBTML_SICF_SHIFT)) |
272	        (val << SBTML_SICF_SHIFT);
273	W_SBREG(sii, &sb->sbtmstatelow, w);
274}
275
276/* set/clear core-specific control flags */
277uint32
278sb_core_cflags(si_t *sih, uint32 mask, uint32 val)
279{
280	si_info_t *sii;
281	sbconfig_t *sb;
282	uint32 w;
283
284	sii = SI_INFO(sih);
285	sb = REGS2SB(sii->curmap);
286
287	ASSERT((val & ~mask) == 0);
288
289	/* mask and set */
290	if (mask || val) {
291		w = (R_SBREG(sii, &sb->sbtmstatelow) & ~(mask << SBTML_SICF_SHIFT)) |
292		        (val << SBTML_SICF_SHIFT);
293		W_SBREG(sii, &sb->sbtmstatelow, w);
294	}
295
296	/* return the new value
297	 * for write operation, the following readback ensures the completion of write opration.
298	 */
299	return (R_SBREG(sii, &sb->sbtmstatelow) >> SBTML_SICF_SHIFT);
300}
301
302/* set/clear core-specific status flags */
303uint32
304sb_core_sflags(si_t *sih, uint32 mask, uint32 val)
305{
306	si_info_t *sii;
307	sbconfig_t *sb;
308	uint32 w;
309
310	sii = SI_INFO(sih);
311	sb = REGS2SB(sii->curmap);
312
313	ASSERT((val & ~mask) == 0);
314	ASSERT((mask & ~SISF_CORE_BITS) == 0);
315
316	/* mask and set */
317	if (mask || val) {
318		w = (R_SBREG(sii, &sb->sbtmstatehigh) & ~(mask << SBTMH_SISF_SHIFT)) |
319		        (val << SBTMH_SISF_SHIFT);
320		W_SBREG(sii, &sb->sbtmstatehigh, w);
321	}
322
323	/* return the new value */
324	return (R_SBREG(sii, &sb->sbtmstatehigh) >> SBTMH_SISF_SHIFT);
325}
326
327bool
328sb_iscoreup(si_t *sih)
329{
330	si_info_t *sii;
331	sbconfig_t *sb;
332
333	sii = SI_INFO(sih);
334	sb = REGS2SB(sii->curmap);
335
336	return ((R_SBREG(sii, &sb->sbtmstatelow) &
337	         (SBTML_RESET | SBTML_REJ_MASK | (SICF_CLOCK_EN << SBTML_SICF_SHIFT))) ==
338	        (SICF_CLOCK_EN << SBTML_SICF_SHIFT));
339}
340
341/*
342 * Switch to 'coreidx', issue a single arbitrary 32bit register mask&set operation,
343 * switch back to the original core, and return the new value.
344 *
345 * When using the silicon backplane, no fidleing with interrupts or core switches are needed.
346 *
347 * Also, when using pci/pcie, we can optimize away the core switching for pci registers
348 * and (on newer pci cores) chipcommon registers.
349 */
350uint
351sb_corereg(si_t *sih, uint coreidx, uint regoff, uint mask, uint val)
352{
353	uint origidx = 0;
354	uint32 *r = NULL;
355	uint w;
356	uint intr_val = 0;
357	bool fast = FALSE;
358	si_info_t *sii;
359
360	sii = SI_INFO(sih);
361
362	ASSERT(GOODIDX(coreidx));
363	ASSERT(regoff < SI_CORE_SIZE);
364	ASSERT((val & ~mask) == 0);
365
366	if (coreidx >= SI_MAXCORES)
367		return 0;
368
369	if (BUSTYPE(sii->pub.bustype) == SI_BUS) {
370		/* If internal bus, we can always get at everything */
371		fast = TRUE;
372		/* map if does not exist */
373		if (!sii->common_info->regs[coreidx]) {
374			sii->common_info->regs[coreidx] =
375			    REG_MAP(sii->common_info->coresba[coreidx], SI_CORE_SIZE);
376			ASSERT(GOODREGS(sii->common_info->regs[coreidx]));
377		}
378		r = (uint32 *)((uchar *)sii->common_info->regs[coreidx] + regoff);
379	} else if (BUSTYPE(sii->pub.bustype) == PCI_BUS) {
380		/* If pci/pcie, we can get at pci/pcie regs and on newer cores to chipc */
381
382		if ((sii->common_info->coreid[coreidx] == CC_CORE_ID) && SI_FAST(sii)) {
383			/* Chipc registers are mapped at 12KB */
384
385			fast = TRUE;
386			r = (uint32 *)((char *)sii->curmap + PCI_16KB0_CCREGS_OFFSET + regoff);
387		} else if (sii->pub.buscoreidx == coreidx) {
388			/* pci registers are at either in the last 2KB of an 8KB window
389			 * or, in pcie and pci rev 13 at 8KB
390			 */
391			fast = TRUE;
392			if (SI_FAST(sii))
393				r = (uint32 *)((char *)sii->curmap +
394				               PCI_16KB0_PCIREGS_OFFSET + regoff);
395			else
396				r = (uint32 *)((char *)sii->curmap +
397				               ((regoff >= SBCONFIGOFF) ?
398				                PCI_BAR0_PCISBR_OFFSET : PCI_BAR0_PCIREGS_OFFSET) +
399				               regoff);
400		}
401	}
402
403	if (!fast) {
404		INTR_OFF(sii, intr_val);
405
406		/* save current core index */
407		origidx = si_coreidx(&sii->pub);
408
409		/* switch core */
410		r = (uint32*) ((uchar*)sb_setcoreidx(&sii->pub, coreidx) + regoff);
411	}
412	ASSERT(r != NULL);
413
414	/* mask and set */
415	if (mask || val) {
416		if (regoff >= SBCONFIGOFF) {
417			w = (R_SBREG(sii, r) & ~mask) | val;
418			W_SBREG(sii, r, w);
419		} else {
420			w = (R_REG(sii->osh, r) & ~mask) | val;
421			W_REG(sii->osh, r, w);
422		}
423	}
424
425	/* readback */
426	if (regoff >= SBCONFIGOFF)
427		w = R_SBREG(sii, r);
428	else {
429		if ((CHIPID(sii->pub.chip) == BCM5354_CHIP_ID) &&
430		    (coreidx == SI_CC_IDX) &&
431		    (regoff == OFFSETOF(chipcregs_t, watchdog))) {
432			w = val;
433		} else
434			w = R_REG(sii->osh, r);
435	}
436
437	if (!fast) {
438		/* restore core index */
439		if (origidx != coreidx)
440			sb_setcoreidx(&sii->pub, origidx);
441
442		INTR_RESTORE(sii, intr_val);
443	}
444
445	return (w);
446}
447
448/* Scan the enumeration space to find all cores starting from the given
449 * bus 'sbba'. Append coreid and other info to the lists in 'si'. 'sba'
450 * is the default core address at chip POR time and 'regs' is the virtual
451 * address that the default core is mapped at. 'ncores' is the number of
452 * cores expected on bus 'sbba'. It returns the total number of cores
453 * starting from bus 'sbba', inclusive.
454 */
455#define SB_MAXBUSES	2
456static uint
457_sb_scan(si_info_t *sii, uint32 sba, void *regs, uint bus, uint32 sbba, uint numcores)
458{
459	uint next;
460	uint ncc = 0;
461	uint i;
462
463	if (bus >= SB_MAXBUSES) {
464		SI_ERROR(("_sb_scan: bus 0x%08x at level %d is too deep to scan\n", sbba, bus));
465		return 0;
466	}
467	SI_MSG(("_sb_scan: scan bus 0x%08x assume %u cores\n", sbba, numcores));
468
469	/* Scan all cores on the bus starting from core 0.
470	 * Core addresses must be contiguous on each bus.
471	 */
472	for (i = 0, next = sii->numcores; i < numcores && next < SB_BUS_MAXCORES; i++, next++) {
473		sii->common_info->coresba[next] = sbba + (i * SI_CORE_SIZE);
474
475		/* keep and reuse the initial register mapping */
476		if ((BUSTYPE(sii->pub.bustype) == SI_BUS) &&
477			(sii->common_info->coresba[next] == sba)) {
478			SI_MSG(("_sb_scan: reuse mapped regs %p for core %u\n", regs, next));
479			sii->common_info->regs[next] = regs;
480		}
481
482		/* change core to 'next' and read its coreid */
483		sii->curmap = _sb_setcoreidx(sii, next);
484		sii->curidx = next;
485
486		sii->common_info->coreid[next] = sb_coreid(&sii->pub);
487
488		/* core specific processing... */
489		/* chipc provides # cores */
490		if (sii->common_info->coreid[next] == CC_CORE_ID) {
491			chipcregs_t *cc = (chipcregs_t *)sii->curmap;
492			uint32 ccrev = sb_corerev(&sii->pub);
493
494			/* determine numcores - this is the total # cores in the chip */
495			if (((ccrev == 4) || (ccrev >= 6)))
496				numcores = (R_REG(sii->osh, &cc->chipid) & CID_CC_MASK) >>
497				        CID_CC_SHIFT;
498			else {
499				/* Older chips */
500				uint chip = sii->pub.chip;
501
502				if (chip == BCM4306_CHIP_ID)	/* < 4306c0 */
503					numcores = 6;
504				else if (chip == BCM4704_CHIP_ID)
505					numcores = 9;
506				else if (chip == BCM5365_CHIP_ID)
507					numcores = 7;
508				else {
509					SI_ERROR(("sb_chip2numcores: unsupported chip 0x%x\n",
510					          chip));
511					ASSERT(0);
512					numcores = 1;
513				}
514			}
515			SI_MSG(("_sb_scan: there are %u cores in the chip %s\n", numcores,
516				sii->pub.issim ? "QT" : ""));
517		}
518		/* scan bridged SB(s) and add results to the end of the list */
519		else if (sii->common_info->coreid[next] == OCP_CORE_ID) {
520			sbconfig_t *sb = REGS2SB(sii->curmap);
521			uint32 nsbba = R_SBREG(sii, &sb->sbadmatch1);
522			uint nsbcc;
523
524			sii->numcores = next + 1;
525
526			if ((nsbba & 0xfff00000) != SI_ENUM_BASE)
527				continue;
528			nsbba &= 0xfffff000;
529			if (_sb_coreidx(sii, nsbba) != BADIDX)
530				continue;
531
532			nsbcc = (R_SBREG(sii, &sb->sbtmstatehigh) & 0x000f0000) >> 16;
533			nsbcc = _sb_scan(sii, sba, regs, bus + 1, nsbba, nsbcc);
534			if (sbba == SI_ENUM_BASE)
535				numcores -= nsbcc;
536			ncc += nsbcc;
537		}
538	}
539
540	SI_MSG(("_sb_scan: found %u cores on bus 0x%08x\n", i, sbba));
541
542	sii->numcores = i + ncc;
543	return sii->numcores;
544}
545
546/* scan the sb enumerated space to identify all cores */
547void
548sb_scan(si_t *sih, void *regs, uint devid)
549{
550	si_info_t *sii;
551	uint32 origsba;
552
553	sii = SI_INFO(sih);
554
555	/* Save the current core info and validate it later till we know
556	 * for sure what is good and what is bad.
557	 */
558	origsba = _sb_coresba(sii);
559
560	/* scan all SB(s) starting from SI_ENUM_BASE */
561	sii->numcores = _sb_scan(sii, origsba, regs, 0, SI_ENUM_BASE, 1);
562}
563
564/*
565 * This function changes logical "focus" to the indicated core;
566 * must be called with interrupts off.
567 * Moreover, callers should keep interrupts off during switching out of and back to d11 core
568 */
569void *
570sb_setcoreidx(si_t *sih, uint coreidx)
571{
572	si_info_t *sii;
573
574	sii = SI_INFO(sih);
575
576	if (coreidx >= sii->numcores)
577		return (NULL);
578
579	/*
580	 * If the user has provided an interrupt mask enabled function,
581	 * then assert interrupts are disabled before switching the core.
582	 */
583	ASSERT((sii->intrsenabled_fn == NULL) || !(*(sii)->intrsenabled_fn)((sii)->intr_arg));
584
585	sii->curmap = _sb_setcoreidx(sii, coreidx);
586	sii->curidx = coreidx;
587
588	return (sii->curmap);
589}
590
591/* This function changes the logical "focus" to the indicated core.
592 * Return the current core's virtual address.
593 */
594static void *
595_sb_setcoreidx(si_info_t *sii, uint coreidx)
596{
597	uint32 sbaddr = sii->common_info->coresba[coreidx];
598	void *regs;
599
600	switch (BUSTYPE(sii->pub.bustype)) {
601	case SI_BUS:
602		/* map new one */
603		if (!sii->common_info->regs[coreidx]) {
604			sii->common_info->regs[coreidx] = REG_MAP(sbaddr, SI_CORE_SIZE);
605			ASSERT(GOODREGS(sii->common_info->regs[coreidx]));
606		}
607		regs = sii->common_info->regs[coreidx];
608		break;
609
610	case PCI_BUS:
611		/* point bar0 window */
612		OSL_PCI_WRITE_CONFIG(sii->osh, PCI_BAR0_WIN, 4, sbaddr);
613		regs = sii->curmap;
614		break;
615
616	case PCMCIA_BUS: {
617		uint8 tmp = (sbaddr >> 12) & 0x0f;
618		OSL_PCMCIA_WRITE_ATTR(sii->osh, PCMCIA_ADDR0, &tmp, 1);
619		tmp = (sbaddr >> 16) & 0xff;
620		OSL_PCMCIA_WRITE_ATTR(sii->osh, PCMCIA_ADDR1, &tmp, 1);
621		tmp = (sbaddr >> 24) & 0xff;
622		OSL_PCMCIA_WRITE_ATTR(sii->osh, PCMCIA_ADDR2, &tmp, 1);
623		regs = sii->curmap;
624		break;
625	}
626	case SPI_BUS:
627	case SDIO_BUS:
628		/* map new one */
629		if (!sii->common_info->regs[coreidx]) {
630			sii->common_info->regs[coreidx] = (void *)(uintptr)sbaddr;
631			ASSERT(GOODREGS(sii->common_info->regs[coreidx]));
632		}
633		regs = sii->common_info->regs[coreidx];
634		break;
635
636
637	default:
638		ASSERT(0);
639		regs = NULL;
640		break;
641	}
642
643	return regs;
644}
645
646/* Return the address of sbadmatch0/1/2/3 register */
647static volatile uint32 *
648sb_admatch(si_info_t *sii, uint asidx)
649{
650	sbconfig_t *sb;
651	volatile uint32 *addrm;
652
653	sb = REGS2SB(sii->curmap);
654
655	switch (asidx) {
656	case 0:
657		addrm =  &sb->sbadmatch0;
658		break;
659
660	case 1:
661		addrm =  &sb->sbadmatch1;
662		break;
663
664	case 2:
665		addrm =  &sb->sbadmatch2;
666		break;
667
668	case 3:
669		addrm =  &sb->sbadmatch3;
670		break;
671
672	default:
673		SI_ERROR(("%s: Address space index (%d) out of range\n", __FUNCTION__, asidx));
674		return 0;
675	}
676
677	return (addrm);
678}
679
680/* Return the number of address spaces in current core */
681int
682sb_numaddrspaces(si_t *sih)
683{
684	si_info_t *sii;
685	sbconfig_t *sb;
686
687	sii = SI_INFO(sih);
688	sb = REGS2SB(sii->curmap);
689
690	/* + 1 because of enumeration space */
691	return ((R_SBREG(sii, &sb->sbidlow) & SBIDL_AR_MASK) >> SBIDL_AR_SHIFT) + 1;
692}
693
694/* Return the address of the nth address space in the current core */
695uint32
696sb_addrspace(si_t *sih, uint asidx)
697{
698	si_info_t *sii;
699
700	sii = SI_INFO(sih);
701
702	return (sb_base(R_SBREG(sii, sb_admatch(sii, asidx))));
703}
704
705/* Return the size of the nth address space in the current core */
706uint32
707sb_addrspacesize(si_t *sih, uint asidx)
708{
709	si_info_t *sii;
710
711	sii = SI_INFO(sih);
712
713	return (sb_size(R_SBREG(sii, sb_admatch(sii, asidx))));
714}
715
716
717/* do buffered registers update */
718void
719sb_commit(si_t *sih)
720{
721	si_info_t *sii;
722	uint origidx;
723	uint intr_val = 0;
724
725	sii = SI_INFO(sih);
726
727	origidx = sii->curidx;
728	ASSERT(GOODIDX(origidx));
729
730	INTR_OFF(sii, intr_val);
731
732	/* switch over to chipcommon core if there is one, else use pci */
733	if (sii->pub.ccrev != NOREV) {
734		chipcregs_t *ccregs = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0);
735
736		/* do the buffer registers update */
737		W_REG(sii->osh, &ccregs->broadcastaddress, SB_COMMIT);
738		W_REG(sii->osh, &ccregs->broadcastdata, 0x0);
739	} else
740		ASSERT(0);
741
742	/* restore core index */
743	sb_setcoreidx(sih, origidx);
744	INTR_RESTORE(sii, intr_val);
745}
746
747void
748sb_core_disable(si_t *sih, uint32 bits)
749{
750	si_info_t *sii;
751	volatile uint32 dummy;
752	sbconfig_t *sb;
753
754	sii = SI_INFO(sih);
755
756	ASSERT(GOODREGS(sii->curmap));
757	sb = REGS2SB(sii->curmap);
758
759	/* if core is already in reset, just return */
760	if (R_SBREG(sii, &sb->sbtmstatelow) & SBTML_RESET)
761		return;
762
763	/* if clocks are not enabled, put into reset and return */
764	if ((R_SBREG(sii, &sb->sbtmstatelow) & (SICF_CLOCK_EN << SBTML_SICF_SHIFT)) == 0)
765		goto disable;
766
767	/* set target reject and spin until busy is clear (preserve core-specific bits) */
768	OR_SBREG(sii, &sb->sbtmstatelow, SBTML_REJ);
769	dummy = R_SBREG(sii, &sb->sbtmstatelow);
770	OSL_DELAY(1);
771	SPINWAIT((R_SBREG(sii, &sb->sbtmstatehigh) & SBTMH_BUSY), 100000);
772	if (R_SBREG(sii, &sb->sbtmstatehigh) & SBTMH_BUSY)
773		SI_ERROR(("%s: target state still busy\n", __FUNCTION__));
774
775	if (R_SBREG(sii, &sb->sbidlow) & SBIDL_INIT) {
776		OR_SBREG(sii, &sb->sbimstate, SBIM_RJ);
777		dummy = R_SBREG(sii, &sb->sbimstate);
778		OSL_DELAY(1);
779		SPINWAIT((R_SBREG(sii, &sb->sbimstate) & SBIM_BY), 100000);
780	}
781
782	/* set reset and reject while enabling the clocks */
783	W_SBREG(sii, &sb->sbtmstatelow,
784	        (((bits | SICF_FGC | SICF_CLOCK_EN) << SBTML_SICF_SHIFT) |
785	         SBTML_REJ | SBTML_RESET));
786	dummy = R_SBREG(sii, &sb->sbtmstatelow);
787	OSL_DELAY(10);
788
789	/* don't forget to clear the initiator reject bit */
790	if (R_SBREG(sii, &sb->sbidlow) & SBIDL_INIT)
791		AND_SBREG(sii, &sb->sbimstate, ~SBIM_RJ);
792
793disable:
794	/* leave reset and reject asserted */
795	W_SBREG(sii, &sb->sbtmstatelow, ((bits << SBTML_SICF_SHIFT) | SBTML_REJ | SBTML_RESET));
796	OSL_DELAY(1);
797}
798
799/* reset and re-enable a core
800 * inputs:
801 * bits - core specific bits that are set during and after reset sequence
802 * resetbits - core specific bits that are set only during reset sequence
803 */
804void
805sb_core_reset(si_t *sih, uint32 bits, uint32 resetbits)
806{
807	si_info_t *sii;
808	sbconfig_t *sb;
809	volatile uint32 dummy;
810
811	sii = SI_INFO(sih);
812	ASSERT(GOODREGS(sii->curmap));
813	sb = REGS2SB(sii->curmap);
814
815	/*
816	 * Must do the disable sequence first to work for arbitrary current core state.
817	 */
818	sb_core_disable(sih, (bits | resetbits));
819
820	/*
821	 * Now do the initialization sequence.
822	 */
823
824	/* set reset while enabling the clock and forcing them on throughout the core */
825	W_SBREG(sii, &sb->sbtmstatelow,
826	        (((bits | resetbits | SICF_FGC | SICF_CLOCK_EN) << SBTML_SICF_SHIFT) |
827	         SBTML_RESET));
828	dummy = R_SBREG(sii, &sb->sbtmstatelow);
829	OSL_DELAY(1);
830
831	if (R_SBREG(sii, &sb->sbtmstatehigh) & SBTMH_SERR) {
832		W_SBREG(sii, &sb->sbtmstatehigh, 0);
833	}
834	if ((dummy = R_SBREG(sii, &sb->sbimstate)) & (SBIM_IBE | SBIM_TO)) {
835		AND_SBREG(sii, &sb->sbimstate, ~(SBIM_IBE | SBIM_TO));
836	}
837
838	/* clear reset and allow it to propagate throughout the core */
839	W_SBREG(sii, &sb->sbtmstatelow,
840	        ((bits | resetbits | SICF_FGC | SICF_CLOCK_EN) << SBTML_SICF_SHIFT));
841	dummy = R_SBREG(sii, &sb->sbtmstatelow);
842	OSL_DELAY(1);
843
844	/* leave clock enabled */
845	W_SBREG(sii, &sb->sbtmstatelow, ((bits | SICF_CLOCK_EN) << SBTML_SICF_SHIFT));
846	dummy = R_SBREG(sii, &sb->sbtmstatelow);
847	OSL_DELAY(1);
848}
849
850void
851sb_core_tofixup(si_t *sih)
852{
853	si_info_t *sii;
854	sbconfig_t *sb;
855
856	sii = SI_INFO(sih);
857
858	if ((BUSTYPE(sii->pub.bustype) != PCI_BUS) || PCIE(sii) ||
859	    (PCI(sii) && (sii->pub.buscorerev >= 5)))
860		return;
861
862	ASSERT(GOODREGS(sii->curmap));
863	sb = REGS2SB(sii->curmap);
864
865	if (BUSTYPE(sii->pub.bustype) == SI_BUS) {
866		SET_SBREG(sii, &sb->sbimconfiglow,
867		          SBIMCL_RTO_MASK | SBIMCL_STO_MASK,
868		          (0x5 << SBIMCL_RTO_SHIFT) | 0x3);
869	} else {
870		if (sb_coreid(sih) == PCI_CORE_ID) {
871			SET_SBREG(sii, &sb->sbimconfiglow,
872			          SBIMCL_RTO_MASK | SBIMCL_STO_MASK,
873			          (0x3 << SBIMCL_RTO_SHIFT) | 0x2);
874		} else {
875			SET_SBREG(sii, &sb->sbimconfiglow, (SBIMCL_RTO_MASK | SBIMCL_STO_MASK), 0);
876		}
877	}
878
879	sb_commit(sih);
880}
881
882/*
883 * Set the initiator timeout for the "master core".
884 * The master core is defined to be the core in control
885 * of the chip and so it issues accesses to non-memory
886 * locations (Because of dma *any* core can access memeory).
887 *
888 * The routine uses the bus to decide who is the master:
889 *	SI_BUS => mips
890 *	JTAG_BUS => chipc
891 *	PCI_BUS => pci or pcie
892 *	PCMCIA_BUS => pcmcia
893 *	SDIO_BUS => pcmcia
894 *
895 * This routine exists so callers can disable initiator
896 * timeouts so accesses to very slow devices like otp
897 * won't cause an abort. The routine allows arbitrary
898 * settings of the service and request timeouts, though.
899 *
900 * Returns the timeout state before changing it or -1
901 * on error.
902 */
903
904#define	TO_MASK	(SBIMCL_RTO_MASK | SBIMCL_STO_MASK)
905
906uint32
907sb_set_initiator_to(si_t *sih, uint32 to, uint idx)
908{
909	si_info_t *sii;
910	uint origidx;
911	uint intr_val = 0;
912	uint32 tmp, ret = 0xffffffff;
913	sbconfig_t *sb;
914
915	sii = SI_INFO(sih);
916
917	if ((to & ~TO_MASK) != 0)
918		return ret;
919
920	/* Figure out the master core */
921	if (idx == BADIDX) {
922		switch (BUSTYPE(sii->pub.bustype)) {
923		case PCI_BUS:
924			idx = sii->pub.buscoreidx;
925			break;
926		case JTAG_BUS:
927			idx = SI_CC_IDX;
928			break;
929		case PCMCIA_BUS:
930		case SDIO_BUS:
931			idx = si_findcoreidx(sih, PCMCIA_CORE_ID, 0);
932			break;
933		case SI_BUS:
934			idx = si_findcoreidx(sih, MIPS33_CORE_ID, 0);
935			break;
936		default:
937			ASSERT(0);
938		}
939		if (idx == BADIDX)
940			return ret;
941	}
942
943	INTR_OFF(sii, intr_val);
944	origidx = si_coreidx(sih);
945
946	sb = REGS2SB(sb_setcoreidx(sih, idx));
947
948	tmp = R_SBREG(sii, &sb->sbimconfiglow);
949	ret = tmp & TO_MASK;
950	W_SBREG(sii, &sb->sbimconfiglow, (tmp & ~TO_MASK) | to);
951
952	sb_commit(sih);
953	sb_setcoreidx(sih, origidx);
954	INTR_RESTORE(sii, intr_val);
955	return ret;
956}
957
958uint32
959sb_base(uint32 admatch)
960{
961	uint32 base;
962	uint type;
963
964	type = admatch & SBAM_TYPE_MASK;
965	ASSERT(type < 3);
966
967	base = 0;
968
969	if (type == 0) {
970		base = admatch & SBAM_BASE0_MASK;
971	} else if (type == 1) {
972		ASSERT(!(admatch & SBAM_ADNEG));	/* neg not supported */
973		base = admatch & SBAM_BASE1_MASK;
974	} else if (type == 2) {
975		ASSERT(!(admatch & SBAM_ADNEG));	/* neg not supported */
976		base = admatch & SBAM_BASE2_MASK;
977	}
978
979	return (base);
980}
981
982uint32
983sb_size(uint32 admatch)
984{
985	uint32 size;
986	uint type;
987
988	type = admatch & SBAM_TYPE_MASK;
989	ASSERT(type < 3);
990
991	size = 0;
992
993	if (type == 0) {
994		size = 1 << (((admatch & SBAM_ADINT0_MASK) >> SBAM_ADINT0_SHIFT) + 1);
995	} else if (type == 1) {
996		ASSERT(!(admatch & SBAM_ADNEG));	/* neg not supported */
997		size = 1 << (((admatch & SBAM_ADINT1_MASK) >> SBAM_ADINT1_SHIFT) + 1);
998	} else if (type == 2) {
999		ASSERT(!(admatch & SBAM_ADNEG));	/* neg not supported */
1000		size = 1 << (((admatch & SBAM_ADINT2_MASK) >> SBAM_ADINT2_SHIFT) + 1);
1001	}
1002
1003	return (size);
1004}
1005