1/*
2 * BCM47XX Sonics SiliconBackplane MIPS core routines
3 *
4 * Copyright 2007, Broadcom Corporation
5 * All Rights Reserved.
6 *
7 * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
8 * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
9 * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
10 * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
11 *
12 * $Id: hndmips.c,v 1.1.1.1 2008/10/15 03:31:34 james26_jang Exp $
13 */
14
15#include <typedefs.h>
16#include <bcmdefs.h>
17#include <osl.h>
18#include <bcmutils.h>
19#include <sbutils.h>
20#include <bcmdevs.h>
21#include <bcmnvram.h>
22#include <sbconfig.h>
23#include <sbchipc.h>
24#include <sbmemc.h>
25#include <mipsinc.h>
26#include <sbhndmips.h>
27#include <hndcpu.h>
28#include <hndmips.h>
29
30/* sbipsflag register format, indexed by irq. */
31static const uint32 sbips_int_mask[] = {
32	0,	/* placeholder */
33	SBIPS_INT1_MASK,
34	SBIPS_INT2_MASK,
35	SBIPS_INT3_MASK,
36	SBIPS_INT4_MASK
37};
38
39static const uint32 sbips_int_shift[] = {
40	0,	/* placeholder */
41	SBIPS_INT1_SHIFT,
42	SBIPS_INT2_SHIFT,
43	SBIPS_INT3_SHIFT,
44	SBIPS_INT4_SHIFT
45};
46
47/*
48 * Map SB cores sharing the MIPS hardware IRQ0 to virtual dedicated OS IRQs.
49 * Per-port BSP code is required to provide necessary translations between
50 * the shared MIPS IRQ and the virtual OS IRQs based on SB core flag.
51 *
52 * See sb_irq() for the mapping.
53 */
54static uint shirq_map_base = 0;
55
56/*
57 * Returns the MIPS IRQ assignment of the current core. If unassigned,
58 * 0 is returned.
59 */
60static uint
61sb_getirq(sb_t *sbh)
62{
63	osl_t *osh;
64	uint idx;
65	void *regs;
66	sbconfig_t *sb;
67	uint32 flag, sbipsflag;
68	uint irq = 0;
69
70	osh = sb_osh(sbh);
71	flag = sb_flag(sbh);
72
73	idx = sb_coreidx(sbh);
74
75	if ((regs = sb_setcore(sbh, SB_MIPS33, 0)) != NULL) {
76		sb = (sbconfig_t *)((ulong) regs + SBCONFIGOFF);
77
78		/* sbipsflag specifies which core is routed to interrupts 1 to 4 */
79		sbipsflag = R_REG(osh, &sb->sbipsflag);
80		for (irq = 1; irq <= 4; irq++) {
81			if (((sbipsflag & sbips_int_mask[irq]) >> sbips_int_shift[irq]) == flag)
82				break;
83		}
84		if (irq == 5)
85			irq = 0;
86	}
87
88	sb_setcoreidx(sbh, idx);
89
90	return irq;
91}
92
93/*
94 * Return the MIPS IRQ assignment of the current core. If necessary
95 * map cores sharing the MIPS hw IRQ0 to virtual dedicated OS IRQs.
96 */
97uint
98sb_irq(sb_t *sbh)
99{
100	uint irq = sb_getirq(sbh);
101	if (irq == 0 && shirq_map_base)
102		irq = sb_flag(sbh) + shirq_map_base;
103	return irq;
104}
105
106/* Clears the specified MIPS IRQ. */
107static void
108BCMINITFN(sb_clearirq)(sb_t *sbh, uint irq)
109{
110	osl_t *osh;
111	void *regs;
112	sbconfig_t *sb;
113
114	osh = sb_osh(sbh);
115
116	regs = sb_setcore(sbh, SB_MIPS33, 0);
117	ASSERT(regs);
118	sb = (sbconfig_t *)((ulong) regs + SBCONFIGOFF);
119
120	if (irq == 0)
121		W_REG(osh, &sb->sbintvec, 0);
122	else
123		OR_REG(osh, &sb->sbipsflag, sbips_int_mask[irq]);
124}
125
126/*
127 * Assigns the specified MIPS IRQ to the specified core. Shared MIPS
128 * IRQ 0 may be assigned more than once.
129 *
130 * The old assignment to the specified core is removed first.
131 */
132static void
133BCMINITFN(sb_setirq)(sb_t *sbh, uint irq, uint coreid, uint coreunit)
134{
135	osl_t *osh;
136	void *regs;
137	sbconfig_t *sb;
138	uint32 flag;
139	uint oldirq;
140
141	osh = sb_osh(sbh);
142
143	regs = sb_setcore(sbh, coreid, coreunit);
144	ASSERT(regs);
145	flag = sb_flag(sbh);
146	oldirq = sb_getirq(sbh);
147	if (oldirq)
148		sb_clearirq(sbh, oldirq);
149
150	regs = sb_setcore(sbh, SB_MIPS33, 0);
151	ASSERT(regs);
152	sb = (sbconfig_t *)((ulong) regs + SBCONFIGOFF);
153
154	if (!oldirq)
155		AND_REG(osh, &sb->sbintvec, ~(1 << flag));
156
157	if (irq == 0)
158		OR_REG(osh, &sb->sbintvec, 1 << flag);
159	else {
160		flag <<= sbips_int_shift[irq];
161		ASSERT(!(flag & ~sbips_int_mask[irq]));
162		flag |= R_REG(osh, &sb->sbipsflag) & ~sbips_int_mask[irq];
163		W_REG(osh, &sb->sbipsflag, flag);
164	}
165}
166
167/*
168 * Initializes clocks and interrupts. SB and NVRAM access must be
169 * initialized prior to calling.
170 *
171 * 'shirqmap' enables virtual dedicated OS IRQ mapping if non-zero.
172 */
173void
174BCMINITFN(sb_mips_init)(sb_t *sbh, uint shirqmap)
175{
176	osl_t *osh;
177	ulong hz, ns, tmp;
178	chipcregs_t *cc;
179	uint irq;
180
181	osh = sb_osh(sbh);
182
183	/* Figure out current SB clock speed */
184	if ((hz = sb_clock(sbh)) == 0)
185		hz = 100000000;
186	ns = 1000000000 / hz;
187
188	/* Setup external interface timing */
189	cc = sb_setcore(sbh, SB_CC, 0);
190	ASSERT(cc);
191
192	/* Set timing for the flash */
193	tmp = CEIL(10, ns) << FW_W3_SHIFT;	/* W3 = 10nS */
194	tmp |= CEIL(10, ns) << FW_W1_SHIFT;	/* W1 = 10nS */
195	tmp |= CEIL(120, ns);			/* W0 = 120nS */
196	if (sbh->ccrev < 9)
197		W_REG(osh, &cc->flash_waitcount, tmp);
198
199	if ((sbh->ccrev < 9) ||
200	    ((sb_chip(sbh) == BCM5350_CHIP_ID) && sb_chiprev(sbh) == 0)) {
201		W_REG(osh, &cc->pcmcia_memwait, tmp);
202	}
203
204	/* Save shared IRQ mapping base */
205	shirq_map_base = shirqmap;
206
207	/* Chip specific initialization */
208	switch (sb_chip(sbh)) {
209	case BCM5350_CHIP_ID:
210		/* Clear interrupt map */
211		for (irq = 0; irq <= 4; irq++)
212			sb_clearirq(sbh, irq);
213		sb_setirq(sbh, 0, SB_CC, 0);
214		sb_setirq(sbh, 0, SB_MIPS33, 0);
215		sb_setirq(sbh, 1, SB_D11, 0);
216		sb_setirq(sbh, 2, SB_ENET, 0);
217		sb_setirq(sbh, 3, SB_PCI, 0);
218		sb_setirq(sbh, 4, SB_USB, 0);
219		break;
220	case BCM4785_CHIP_ID:
221		/* Reassign PCI to irq 4 */
222		sb_setirq(sbh, 4, SB_PCI, 0);
223		break;
224	}
225}
226
227/* Do any setup necessary to run a new image and jump to it. */
228void
229hnd_cpu_jumpto(void *addr)
230{
231	void (*jumpto)(void) = addr;
232
233	(jumpto)();
234}
235
236uint32
237BCMINITFN(sb_cpu_clock)(sb_t *sbh)
238{
239	chipcregs_t *cc;
240	uint32 n, m;
241	uint idx;
242	uint32 pll_type, rate = 0;
243
244	/* get index of the current core */
245	idx = sb_coreidx(sbh);
246	pll_type = PLL_TYPE1;
247
248	/* switch to chipc core */
249	cc = (chipcregs_t *) sb_setcore(sbh, SB_CC, 0);
250	ASSERT(cc);
251
252	/* 5354 chip uses a non programmable PLL of frequency 240MHz */
253	if (sb_chip(sbh) == BCM5354_CHIP_ID) {
254		//rate = 240000000;
255		rate = 200000000;
256		goto out;
257	}
258
259	pll_type = sbh->cccaps & CC_CAP_PLL_MASK;
260	n = R_REG(osh, &cc->clockcontrol_n);
261	if ((pll_type == PLL_TYPE2) ||
262	    (pll_type == PLL_TYPE4) ||
263	    (pll_type == PLL_TYPE6) ||
264	    (pll_type == PLL_TYPE7))
265		m = R_REG(osh, &cc->clockcontrol_m3);
266	else if (pll_type == PLL_TYPE5) {
267		rate = 200000000;
268		goto out;
269	} else if (pll_type == PLL_TYPE3) {
270		if (sb_chip(sbh) == BCM5365_CHIP_ID) {
271			rate = 200000000;
272			goto out;
273		}
274		/* 5350 uses m2 to control mips */
275		else
276			m = R_REG(osh, &cc->clockcontrol_m2);
277	} else
278		m = R_REG(osh, &cc->clockcontrol_sb);
279
280	/* calculate rate */
281	rate = sb_clock_rate(pll_type, n, m);
282
283	if (pll_type == PLL_TYPE6)
284		rate = SB2MIPS_T6(rate);
285
286out:
287	/* switch back to previous core */
288	sb_setcoreidx(sbh, idx);
289
290	return rate;
291}
292
293#define ALLINTS (IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4)
294
295static void
296BCMINITFN(handler)(void)
297{
298	__asm__(
299		".set\tmips32\n\t"
300		"ssnop\n\t"
301		"ssnop\n\t"
302	/* Disable interrupts */
303	/*	MTC0(C0_STATUS, 0, MFC0(C0_STATUS, 0) & ~(ALLINTS | STO_IE)); */
304		"mfc0 $15, $12\n\t"
305	/* Just a Hack to not to use reg 'at' which was causing problems on 4704 A2 */
306		"li $14, -31746\n\t"
307		"and $15, $15, $14\n\t"
308		"mtc0 $15, $12\n\t"
309		"eret\n\t"
310		"nop\n\t"
311		"nop\n\t"
312		".set\tmips0");
313}
314
315/* The following MUST come right after handler() */
316static void
317BCMINITFN(afterhandler)(void)
318{
319}
320
321/*
322 * Set the MIPS, backplane and PCI clocks as closely as possible.
323 *
324 * MIPS clocks synchronization function has been moved from PLL in chipcommon
325 * core rev. 15 to a DLL inside the MIPS core in 4785.
326 */
327bool
328BCMINITFN(sb_mips_setclock)(sb_t *sbh, uint32 mipsclock, uint32 sbclock, uint32 pciclock)
329{
330	chipcregs_t *cc = NULL;
331	mipsregs_t *mipsr = NULL;
332	volatile uint32 *clockcontrol_n, *clockcontrol_sb, *clockcontrol_pci, *clockcontrol_m2;
333	uint32 orig_n, orig_sb, orig_pci, orig_m2, orig_mips, orig_ratio_parm, orig_ratio_cfg;
334	uint32 pll_type, sync_mode;
335	uint ic_size, ic_lsize;
336	uint idx, i;
337
338	/* PLL configuration: type 1 */
339	typedef struct {
340		uint32 mipsclock;
341		uint16 n;
342		uint32 sb;
343		uint32 pci33;
344		uint32 pci25;
345	} n3m_table_t;
346	static n3m_table_t BCMINITDATA(type1_table)[] = {
347		/* 96.000 32.000 24.000 */
348		{ 96000000, 0x0303, 0x04020011, 0x11030011, 0x11050011 },
349		/* 100.000 33.333 25.000 */
350		{ 100000000, 0x0009, 0x04020011, 0x11030011, 0x11050011 },
351		/* 104.000 31.200 24.960 */
352		{ 104000000, 0x0802, 0x04020011, 0x11050009, 0x11090009 },
353		/* 108.000 32.400 24.923 */
354		{ 108000000, 0x0403, 0x04020011, 0x11050009, 0x02000802 },
355		/* 112.000 32.000 24.889 */
356		{ 112000000, 0x0205, 0x04020011, 0x11030021, 0x02000403 },
357		/* 115.200 32.000 24.000 */
358		{ 115200000, 0x0303, 0x04020009, 0x11030011, 0x11050011 },
359		/* 120.000 30.000 24.000 */
360		{ 120000000, 0x0011, 0x04020011, 0x11050011, 0x11090011 },
361		/* 124.800 31.200 24.960 */
362		{ 124800000, 0x0802, 0x04020009, 0x11050009, 0x11090009 },
363		/* 128.000 32.000 24.000 */
364		{ 128000000, 0x0305, 0x04020011, 0x11050011, 0x02000305 },
365		/* 132.000 33.000 24.750 */
366		{ 132000000, 0x0603, 0x04020011, 0x11050011, 0x02000305 },
367		/* 136.000 32.640 24.727 */
368		{ 136000000, 0x0c02, 0x04020011, 0x11090009, 0x02000603 },
369		/* 140.000 30.000 24.706 */
370		{ 140000000, 0x0021, 0x04020011, 0x11050021, 0x02000c02 },
371		/* 144.000 30.857 24.686 */
372		{ 144000000, 0x0405, 0x04020011, 0x01020202, 0x11090021 },
373		/* 150.857 33.000 24.000 */
374		{ 150857142, 0x0605, 0x04020021, 0x02000305, 0x02000605 },
375		/* 152.000 32.571 24.000 */
376		{ 152000000, 0x0e02, 0x04020011, 0x11050021, 0x02000e02 },
377		/* 156.000 31.200 24.960 */
378		{ 156000000, 0x0802, 0x04020005, 0x11050009, 0x11090009 },
379		/* 160.000 32.000 24.000 */
380		{ 160000000, 0x0309, 0x04020011, 0x11090011, 0x02000309 },
381		/* 163.200 32.640 24.727 */
382		{ 163200000, 0x0c02, 0x04020009, 0x11090009, 0x02000603 },
383		/* 168.000 32.000 24.889 */
384		{ 168000000, 0x0205, 0x04020005, 0x11030021, 0x02000403 },
385		/* 176.000 33.000 24.000 */
386		{ 176000000, 0x0602, 0x04020003, 0x11050005, 0x02000602 },
387		};
388
389	/* PLL configuration: type 3 */
390	typedef struct {
391		uint32 mipsclock;
392		uint16 n;
393		uint32 m2; /* that is the clockcontrol_m2 */
394	} type3_table_t;
395	static type3_table_t type3_table[] = {
396		/* for 5350, mips clock is always double sb clock */
397		{ 150000000, 0x311, 0x4020005 },
398		{ 200000000, 0x311, 0x4020003 },
399		};
400
401	/* PLL configuration: type 2, 4, 7 */
402	typedef struct {
403		uint32 mipsclock;
404		uint32 sbclock;
405		uint32 pciclock;
406		uint16 n;
407		uint32 sb;
408		uint32 pci33;
409		uint32 m2;
410		uint32 m3;
411		uint32 ratio_cfg;
412		uint32 ratio_parm;
413		uint32 d11_r1;
414		uint32 d11_r2;
415	} n4m_table_t;
416	static n4m_table_t BCMINITDATA(type2_table)[] = {
417		{ 120000000, 60000000, 32000000, 0x0303, 0x01000200, 0x01000600, 0x01000200,
418		0x05000200, 11, 0x0aaa0555, 8 /* ratio  4/8 */, 0x00aa0055 },
419		{ 150000000, 75000000, 33333333, 0x0303, 0x01000100, 0x01000600, 0x01000100,
420		0x05000100, 11, 0x0aaa0555, 8 /* ratio  4/8 */, 0x00aa0055 },
421		{ 180000000, 80000000, 30000000, 0x0403, 0x01010000, 0x01020300, 0x01020600,
422		0x05000100, 8, 0x012a00a9, 9 /* ratio  4/9 */, 0x012a00a9 },
423		{ 180000000, 90000000, 30000000, 0x0403, 0x01000100, 0x01020300, 0x01000100,
424		0x05000100, 11, 0x0aaa0555, 8 /* ratio  4/8 */, 0x00aa0055 },
425		{ 200000000, 100000000, 33333333, 0x0303, 0x02010000, 0x02040001, 0x02010000,
426		0x06000001, 11, 0x0aaa0555, 8 /* ratio  4/8 */, 0x00aa0055 },
427		{ 211200000, 105600000, 30171428, 0x0902, 0x01000200, 0x01030400, 0x01000200,
428		0x05000200, 11, 0x0aaa0555, 8 /* ratio  4/8 */, 0x00aa0055 },
429		{ 220800000, 110400000, 31542857, 0x1500, 0x01000200, 0x01030400, 0x01000200,
430		0x05000200, 11, 0x0aaa0555, 8 /* ratio  4/8 */, 0x00aa0055 },
431		{ 230400000, 115200000, 32000000, 0x0604, 0x01000200, 0x01020600, 0x01000200,
432		0x05000200, 11, 0x0aaa0555, 8 /* ratio  4/8 */, 0x00aa0055 },
433		{ 234000000, 104000000, 31200000, 0x0b01, 0x01010000, 0x01010700, 0x01020600,
434		0x05000100, 8, 0x012a00a9, 9 /* ratio  4/9 */, 0x012a00a9 },
435		{ 240000000, 120000000, 33333333, 0x0803, 0x01000200, 0x01020600, 0x01000200,
436		0x05000200, 11, 0x0aaa0555, 8 /* ratio  4/8 */, 0x00aa0055 },
437		{ 252000000, 126000000, 33333333, 0x0504, 0x01000100, 0x01020500, 0x01000100,
438		0x05000100, 11, 0x0aaa0555, 8 /* ratio  4/8 */, 0x00aa0055 },
439		{ 264000000, 132000000, 33000000, 0x0903, 0x01000200, 0x01020700, 0x01000200,
440		0x05000200, 11, 0x0aaa0555, 8 /* ratio  4/8 */, 0x00aa0055 },
441		{ 270000000, 120000000, 30000000, 0x0703, 0x01010000, 0x01030400, 0x01020600,
442		0x05000100, 8, 0x012a00a9, 9 /* ratio  4/9 */, 0x012a00a9 },
443		{ 276000000, 122666666, 31542857, 0x1500, 0x01010000, 0x01030400, 0x01020600,
444		0x05000100, 8, 0x012a00a9, 9 /* ratio  4/9 */, 0x012a00a9 },
445		{ 280000000, 140000000, 31111111, 0x0503, 0x01000000, 0x01010600, 0x01000000,
446		0x05000000, 11, 0x0aaa0555, 8 /* ratio  4/8 */, 0x00aa0055 },
447		{ 288000000, 128000000, 32914285, 0x0604, 0x01010000, 0x01030400, 0x01020600,
448		0x05000100, 8, 0x012a00a9, 9 /* ratio  4/9 */, 0x012a00a9 },
449		{ 288000000, 144000000, 32000000, 0x0404, 0x01000000, 0x01010600, 0x01000000,
450		0x05000000, 11, 0x0aaa0555, 8 /* ratio  4/8 */, 0x00aa0055 },
451		{ 300000000, 133333333, 33333333, 0x0803, 0x01010000, 0x01020600, 0x01010100,
452		0x05000100, 8, 0x012a00a9, 9 /* ratio  4/9 */, 0x012a00a9 },
453		{ 300000000, 133333333, 37500000, 0x0803, 0x01010000, 0x01020500, 0x01010100,
454		0x05000100, 8, 0x012a00a9, 9 /* ratio  4/9 */, 0x012a00a9 },
455		{ 300000000, 133333333, 42857142, 0x0803, 0x01010000, 0x01020400, 0x01010100,
456		0x05000100, 8, 0x012a00a9, 9 /* ratio  4/9 */, 0x012a00a9 },
457		{ 300000000, 133333333, 50000000, 0x0803, 0x01010000, 0x01020300, 0x01010100,
458		0x05000100, 8, 0x012a00a9, 9 /* ratio  4/9 */, 0x012a00a9 },
459		{ 300000000, 133333333, 60000000, 0x0803, 0x01010000, 0x01020200, 0x01010100,
460		0x05000100, 8, 0x012a00a9, 9 /* ratio  4/9 */, 0x012a00a9 },
461		{ 300000000, 150000000, 33333333, 0x0803, 0x01000100, 0x01020600, 0x01010100,
462		0x05000100, 11, 0x0aaa0555, 8 /* ratio  4/8 */, 0x00aa0055 },
463		{ 300000000, 150000000, 37500000, 0x0803, 0x01000100, 0x01020500, 0x01010100,
464		0x05000100, 11, 0x0aaa0555, 8 /* ratio  4/8 */, 0x00aa0055 },
465		{ 300000000, 150000000, 42857142, 0x0803, 0x01000100, 0x01020400, 0x01010100,
466		0x05000100, 11, 0x0aaa0555, 8 /* ratio  4/8 */, 0x00aa0055 },
467		{ 300000000, 150000000, 50000000, 0x0803, 0x01000100, 0x01020300, 0x01010100,
468		0x05000100, 11, 0x0aaa0555, 8 /* ratio  4/8 */, 0x00aa0055 },
469		{ 300000000, 150000000, 60000000, 0x0803, 0x01000100, 0x01020200, 0x01010100,
470		0x05000100, 11, 0x0aaa0555, 8 /* ratio  4/8 */, 0x00aa0055 },
471		{ 330000000, 132000000, 33000000, 0x0903, 0x01000200, 0x00020200, 0x01010100,
472		0x05000100, 0, 0, 10 /* ratio 4/10 */, 0x02520129 },
473		{ 330000000, 146666666, 33000000, 0x0903, 0x01010000, 0x00020200, 0x01010100,
474		0x05000100, 0, 0, 9 /* ratio 4/9 */, 0x012a00a9 },
475		{ 330000000, 165000000, 33000000, 0x0903, 0x01000100, 0x00020200, 0x01010100,
476		0x05000100, 0, 0, 8 /* ratio 4/8 */, 0x00aa0055 },
477		{ 330000000, 165000000, 41250000, 0x0903, 0x01000100, 0x00020100, 0x01010100,
478		0x05000100, 0, 0, 8 /* ratio 4/8 */, 0x00aa0055 },
479		{ 330000000, 165000000, 55000000, 0x0903, 0x01000100, 0x00020000, 0x01010100,
480		0x05000100, 0, 0, 8 /* ratio 4/8 */, 0x00aa0055 },
481		{ 360000000, 120000000, 32000000, 0x0a03, 0x01000300, 0x00010201, 0x01010200,
482		0x05000100, 0, 0, 12 /* ratio 4/12 */, 0x04920492 },
483		{ 360000000, 144000000, 32000000, 0x0a03, 0x01000200, 0x00010201, 0x01010200,
484		0x05000100, 0, 0, 10 /* ratio 4/10 */, 0x02520129 },
485		{ 360000000, 160000000, 32000000, 0x0a03, 0x01010000, 0x00010201, 0x01010200,
486		0x05000100, 0, 0, 9 /* ratio 4/9 */, 0x012a00a9 },
487		{ 360000000, 180000000, 32000000, 0x0a03, 0x01000100, 0x00010201, 0x01010200,
488		0x05000100, 0, 0, 8 /* ratio 4/8 */, 0x00aa0055 },
489		{ 360000000, 180000000, 40000000, 0x0a03, 0x01000100, 0x00010101, 0x01010200,
490		0x05000100, 0, 0, 8 /* ratio 4/8 */, 0x00aa0055 },
491		{ 360000000, 180000000, 53333333, 0x0a03, 0x01000100, 0x00010001, 0x01010200,
492		0x05000100, 0, 0, 8 /* ratio 4/8 */, 0x00aa0055 },
493		{ 390000000, 130000000, 32500000, 0x0b03, 0x01010100, 0x00020101, 0x01020100,
494		0x05000100, 0, 0, 12 /* ratio 4/12 */, 0x04920492 },
495		{ 390000000, 156000000, 32500000, 0x0b03, 0x01000200, 0x00020101, 0x01020100,
496		0x05000100, 0, 0, 10 /* ratio 4/10 */, 0x02520129 },
497		{ 390000000, 173000000, 32500000, 0x0b03, 0x01010000, 0x00020101, 0x01020100,
498		0x05000100, 0, 0, 9 /* ratio 4/9 */, 0x012a00a9 },
499		{ 390000000, 195000000, 32500000, 0x0b03, 0x01000100, 0x00020101, 0x01020100,
500		0x05000100, 0, 0, 8 /* ratio 4/8 */, 0x00aa0055 },
501	};
502	static n4m_table_t BCMINITDATA(type4_table)[] = {
503		{ 120000000, 60000000, 0, 0x0009, 0x11020009, 0x01030203, 0x11020009, 0x04000009,
504		11, 0x0aaa0555 },
505		{ 150000000, 75000000, 0, 0x0009, 0x11050002, 0x01030203, 0x11050002, 0x04000005,
506		11, 0x0aaa0555 },
507		{ 192000000, 96000000, 0, 0x0702, 0x04000011, 0x11030011, 0x04000011, 0x04000003,
508		11, 0x0aaa0555 },
509		{ 198000000, 99000000, 0, 0x0603, 0x11020005, 0x11030011, 0x11020005, 0x04000005,
510		11, 0x0aaa0555 },
511		{ 200000000, 100000000, 0, 0x0009, 0x04020011, 0x11030011, 0x04020011, 0x04020003,
512		11, 0x0aaa0555 },
513		{ 204000000, 102000000, 0, 0x0c02, 0x11020005, 0x01030303, 0x11020005, 0x04000005,
514		11, 0x0aaa0555 },
515		{ 208000000, 104000000, 0, 0x0802, 0x11030002, 0x11090005, 0x11030002, 0x04000003,
516		11, 0x0aaa0555 },
517		{ 210000000, 105000000, 0, 0x0209, 0x11020005, 0x01030303, 0x11020005, 0x04000005,
518		11, 0x0aaa0555 },
519		{ 216000000, 108000000, 0, 0x0111, 0x11020005, 0x01030303, 0x11020005, 0x04000005,
520		11, 0x0aaa0555 },
521		{ 224000000, 112000000, 0, 0x0205, 0x11030002, 0x02002103, 0x11030002, 0x04000003,
522		11, 0x0aaa0555 },
523		{ 228000000, 101333333, 0, 0x0e02, 0x11030003, 0x11210005, 0x01030305, 0x04000005,
524		8, 0x012a00a9 },
525		{ 228000000, 114000000, 0, 0x0e02, 0x11020005, 0x11210005, 0x11020005, 0x04000005,
526		11, 0x0aaa0555 },
527		{ 240000000, 102857143, 0, 0x0109, 0x04000021, 0x01050203, 0x11030021, 0x04000003,
528		13, 0x254a14a9 },
529		{ 240000000, 120000000, 0, 0x0109, 0x11030002, 0x01050203, 0x11030002, 0x04000003,
530		11, 0x0aaa0555 },
531		{ 252000000, 100800000, 0, 0x0203, 0x04000009, 0x11050005, 0x02000209, 0x04000002,
532		9, 0x02520129 },
533		{ 252000000, 126000000, 0, 0x0203, 0x04000005, 0x11050005, 0x04000005, 0x04000002,
534		11, 0x0aaa0555 },
535		{ 264000000, 132000000, 0, 0x0602, 0x04000005, 0x11050005, 0x04000005, 0x04000002,
536		11, 0x0aaa0555 },
537		{ 272000000, 116571428, 0, 0x0c02, 0x04000021, 0x02000909, 0x02000221, 0x04000003,
538		13, 0x254a14a9 },
539		{ 280000000, 120000000, 0, 0x0209, 0x04000021, 0x01030303, 0x02000221, 0x04000003,
540		13, 0x254a14a9 },
541		{ 288000000, 123428571, 0, 0x0111, 0x04000021, 0x01030303, 0x02000221, 0x04000003,
542		13, 0x254a14a9 },
543		{ 300000000, 120000000, 0, 0x0009, 0x04000009, 0x01030203, 0x02000902, 0x04000002,
544		9, 0x02520129 },
545		{ 300000000, 150000000, 0, 0x0009, 0x04000005, 0x01030203, 0x04000005, 0x04000002,
546		11, 0x0aaa0555 }
547	};
548	static n4m_table_t BCMINITDATA(type7_table)[] = {
549		{ 183333333, 91666666, 0, 0x0605, 0x04000011, 0x11030011, 0x04000011, 0x04000003,
550		11, 0x0aaa0555 },
551		{ 187500000, 93750000, 0, 0x0a03, 0x04000011, 0x11030011, 0x04000011, 0x04000003,
552		11, 0x0aaa0555 },
553		{ 196875000, 98437500, 0, 0x1003, 0x11020005, 0x11050011, 0x11020005, 0x04000005,
554		11, 0x0aaa0555 },
555		{ 200000000, 100000000, 0, 0x0311, 0x04000011, 0x11030011, 0x04000009, 0x04000003,
556		11, 0x0aaa0555 },
557		{ 200000000, 100000000, 0, 0x0311, 0x04020011, 0x11030011, 0x04020011, 0x04020003,
558		11, 0x0aaa0555 },
559		{ 206250000, 103125000, 0, 0x1103, 0x11020005, 0x11050011, 0x11020005, 0x04000005,
560		11, 0x0aaa0555 },
561		{ 212500000, 106250000, 0, 0x0c05, 0x11020005, 0x01030303, 0x11020005, 0x04000005,
562		11, 0x0aaa0555 },
563		{ 215625000, 107812500, 0, 0x1203, 0x11090009, 0x11050005, 0x11020005, 0x04000005,
564		11, 0x0aaa0555 },
565		{ 216666666, 108333333, 0, 0x0805, 0x11020003, 0x11030011, 0x11020003, 0x04000003,
566		11, 0x0aaa0555 },
567		{ 225000000, 112500000, 0, 0x0d03, 0x11020003, 0x11030011, 0x11020003, 0x04000003,
568		11, 0x0aaa0555 },
569		{ 233333333, 116666666, 0, 0x0905, 0x11020003, 0x11030011, 0x11020003, 0x04000003,
570		11, 0x0aaa0555 },
571		{ 237500000, 118750000, 0, 0x0e05, 0x11020005, 0x11210005, 0x11020005, 0x04000005,
572		11, 0x0aaa0555 },
573		{ 240000000, 120000000, 0, 0x0b11, 0x11020009, 0x11210009, 0x11020009, 0x04000009,
574		11, 0x0aaa0555 },
575		{ 250000000, 125000000, 0, 0x0f03, 0x11020003, 0x11210003, 0x11020003, 0x04000003,
576		11, 0x0aaa0555 }
577	};
578
579	ulong start, end, dst;
580	bool ret = FALSE;
581
582	volatile uint32 *dll_ctrl = (volatile uint32 *)0xff400008;
583	volatile uint32 *dll_r1 = (volatile uint32 *)0xff400010;
584	volatile uint32 *dll_r2 = (volatile uint32 *)0xff400018;
585
586	/* get index of the current core */
587	idx = sb_coreidx(sbh);
588	clockcontrol_m2 = NULL;
589
590	/* switch to chipc core */
591	cc = (chipcregs_t *) sb_setcore(sbh, SB_CC, 0);
592	ASSERT(cc);
593
594	/* 5354 chipcommon pll setting can't be changed.
595	 * The PMU on power up comes up with the default clk frequency
596	 * of 240MHz
597	 */
598	if (sb_chip(sbh) == BCM5354_CHIP_ID) {
599		ret = TRUE;
600		goto done;
601	}
602
603	pll_type = sbh->cccaps & CC_CAP_PLL_MASK;
604	if (pll_type == PLL_TYPE6) {
605		clockcontrol_n = NULL;
606		clockcontrol_sb = NULL;
607		clockcontrol_pci = NULL;
608	} else {
609		clockcontrol_n = &cc->clockcontrol_n;
610		clockcontrol_sb = &cc->clockcontrol_sb;
611		clockcontrol_pci = &cc->clockcontrol_pci;
612		clockcontrol_m2 = &cc->clockcontrol_m2;
613	}
614
615	if (pll_type == PLL_TYPE6) {
616		/* Silence compilers */
617		orig_n = orig_sb = orig_pci = 0;
618	} else {
619		/* Store the current clock register values */
620		orig_n = R_REG(osh, clockcontrol_n);
621		orig_sb = R_REG(osh, clockcontrol_sb);
622		orig_pci = R_REG(osh, clockcontrol_pci);
623	}
624
625	if (pll_type == PLL_TYPE1) {
626		/* Keep the current PCI clock if not specified */
627		if (pciclock == 0) {
628			pciclock = sb_clock_rate(pll_type, R_REG(osh, clockcontrol_n),
629			                         R_REG(osh, clockcontrol_pci));
630			pciclock = (pciclock <= 25000000) ? 25000000 : 33000000;
631		}
632
633		/* Search for the closest MIPS clock less than or equal to a preferred value */
634		for (i = 0; i < ARRAYSIZE(type1_table); i++) {
635			ASSERT(type1_table[i].mipsclock ==
636			       sb_clock_rate(pll_type, type1_table[i].n,
637			       type1_table[i].sb));
638			if (type1_table[i].mipsclock > mipsclock)
639				break;
640		}
641		if (i == 0) {
642			ret = FALSE;
643			goto done;
644		} else {
645			ret = TRUE;
646			i--;
647		}
648		ASSERT(type1_table[i].mipsclock <= mipsclock);
649
650		/* No PLL change */
651		if ((orig_n == type1_table[i].n) &&
652		    (orig_sb == type1_table[i].sb) &&
653		    (orig_pci == type1_table[i].pci33))
654			goto done;
655
656		/* Set the PLL controls */
657		W_REG(osh, clockcontrol_n, type1_table[i].n);
658		W_REG(osh, clockcontrol_sb, type1_table[i].sb);
659		if (pciclock == 25000000)
660			W_REG(osh, clockcontrol_pci, type1_table[i].pci25);
661		else
662			W_REG(osh, clockcontrol_pci, type1_table[i].pci33);
663
664		/* Reset */
665		sb_watchdog(sbh, 1);
666		while (1);
667	} else if (pll_type == PLL_TYPE3) {
668		/* 5350 */
669		if (sb_chip(sbh) != BCM5365_CHIP_ID) {
670			/*
671			 * Search for the closest MIPS clock less than or equal to
672			 * a preferred value.
673			 */
674			for (i = 0; i < ARRAYSIZE(type3_table); i++) {
675				if (type3_table[i].mipsclock > mipsclock)
676					break;
677			}
678			if (i == 0) {
679				ret = FALSE;
680				goto done;
681			} else {
682				ret = TRUE;
683				i--;
684			}
685			ASSERT(type3_table[i].mipsclock <= mipsclock);
686
687			/* No PLL change */
688			orig_m2 = R_REG(osh, &cc->clockcontrol_m2);
689			if ((orig_n == type3_table[i].n) &&
690			    (orig_m2 == type3_table[i].m2)) {
691				goto done;
692			}
693
694			/* Set the PLL controls */
695			W_REG(osh, clockcontrol_n, type3_table[i].n);
696			W_REG(osh, clockcontrol_m2, type3_table[i].m2);
697
698			/* Reset */
699			sb_watchdog(sbh, 1);
700			while (1);
701		}
702	} else if ((pll_type == PLL_TYPE2) ||
703	           (pll_type == PLL_TYPE4) ||
704	           (pll_type == PLL_TYPE6) ||
705	           (pll_type == PLL_TYPE7)) {
706		n4m_table_t *table = NULL, *te;
707		uint tabsz = 0;
708
709		ASSERT(cc);
710
711		orig_mips = R_REG(osh, &cc->clockcontrol_m3);
712
713		switch (pll_type) {
714		case PLL_TYPE6: {
715			uint32 new_mips = 0;
716
717			ret = TRUE;
718			if (mipsclock <= SB2MIPS_T6(CC_T6_M1))
719				new_mips = CC_T6_MMASK;
720
721			if (orig_mips == new_mips)
722				goto done;
723
724			W_REG(osh, &cc->clockcontrol_m3, new_mips);
725			goto end_fill;
726		}
727		case PLL_TYPE2:
728			table = type2_table;
729			tabsz = ARRAYSIZE(type2_table);
730			break;
731		case PLL_TYPE4:
732			table = type4_table;
733			tabsz = ARRAYSIZE(type4_table);
734			break;
735		case PLL_TYPE7:
736			table = type7_table;
737			tabsz = ARRAYSIZE(type7_table);
738			break;
739		default:
740			ASSERT("No table for plltype" == NULL);
741			break;
742		}
743
744		/* Store the current clock register values */
745		orig_m2 = R_REG(osh, &cc->clockcontrol_m2);
746		orig_ratio_parm = 0;
747		orig_ratio_cfg = 0;
748
749		/* Look up current ratio */
750		for (i = 0; i < tabsz; i++) {
751			if ((orig_n == table[i].n) &&
752			    (orig_sb == table[i].sb) &&
753			    (orig_pci == table[i].pci33) &&
754			    (orig_m2 == table[i].m2) &&
755			    (orig_mips == table[i].m3)) {
756				orig_ratio_parm = table[i].ratio_parm;
757				orig_ratio_cfg = table[i].ratio_cfg;
758				break;
759			}
760		}
761
762		/* Search for the closest MIPS clock greater or equal to a preferred value */
763		for (i = 0; i < tabsz; i++) {
764			ASSERT(table[i].mipsclock ==
765			       sb_clock_rate(pll_type, table[i].n, table[i].m3));
766			if ((mipsclock <= table[i].mipsclock) &&
767			    ((sbclock == 0) || (sbclock <= table[i].sbclock)) &&
768			    ((pciclock == 0) || (pciclock <= table[i].pciclock)))
769				break;
770		}
771		if (i == tabsz) {
772			ret = FALSE;
773			goto done;
774		} else {
775			te = &table[i];
776			ret = TRUE;
777		}
778
779		/* No PLL change */
780		if ((orig_n == te->n) &&
781		    (orig_sb == te->sb) &&
782		    (orig_pci == te->pci33) &&
783		    (orig_m2 == te->m2) &&
784		    (orig_mips == te->m3))
785			goto done;
786
787		/* Set the PLL controls */
788		W_REG(osh, clockcontrol_n, te->n);
789		W_REG(osh, clockcontrol_sb, te->sb);
790		W_REG(osh, clockcontrol_pci, te->pci33);
791		W_REG(osh, &cc->clockcontrol_m2, te->m2);
792		W_REG(osh, &cc->clockcontrol_m3, te->m3);
793
794		/* Set the chipcontrol bit to change mipsref to the backplane divider if needed */
795		if ((pll_type == PLL_TYPE7) && (te->sb != te->m2) &&
796		    (sb_clock_rate(pll_type, te->n, te->m2) == 120000000))
797			W_REG(osh, &cc->chipcontrol,
798			      R_REG(osh, &cc->chipcontrol) | 0x100);
799
800		/* No ratio change */
801		if (sb_chip(sbh) != BCM4785_CHIP_ID) {
802			if (orig_ratio_parm == te->ratio_parm)
803				goto end_fill;
804		}
805
806		/* Preload the code into the cache */
807		icache_probe(MFC0(C0_CONFIG, 1), &ic_size, &ic_lsize);
808		if (sb_chip(sbh) == BCM4785_CHIP_ID) {
809			start = ((ulong) &&start_fill_4785) & ~(ic_lsize - 1);
810			end = ((ulong) &&end_fill_4785 + (ic_lsize - 1)) & ~(ic_lsize - 1);
811		}
812		else {
813			start = ((ulong) &&start_fill) & ~(ic_lsize - 1);
814			end = ((ulong) &&end_fill + (ic_lsize - 1)) & ~(ic_lsize - 1);
815		}
816		while (start < end) {
817			cache_op(start, Fill_I);
818			start += ic_lsize;
819		}
820
821		/* 4785 clock freq change procedures */
822		if (sb_chip(sbh) == BCM4785_CHIP_ID) {
823	start_fill_4785:
824			/* Switch to async */
825			MTC0(C0_BROADCOM, 4, (1 << 22));
826
827			/* Set clock ratio in MIPS */
828			*dll_r1 = (*dll_r1 & 0xfffffff0) | (te->d11_r1 - 1);
829			*dll_r2 = te->d11_r2;
830
831			/* Enable new settings in MIPS */
832			*dll_r1 = *dll_r1 | 0xc0000000;
833
834			/* Set active cfg */
835			MTC0(C0_BROADCOM, 2, MFC0(C0_BROADCOM, 2) | (1 << 3) | 1);
836
837			/* Fake soft reset (clock cfg registers not reset) */
838			MTC0(C0_BROADCOM, 5, MFC0(C0_BROADCOM, 5) | (1 << 2));
839
840			/* Clear active cfg */
841			MTC0(C0_BROADCOM, 2, MFC0(C0_BROADCOM, 2) & ~(1 << 3));
842
843			/* set watchdog timer */
844			W_REG(osh, &cc->watchdog, 20);
845			(void) R_REG(osh, &cc->chipid);
846
847			/* wait for timer interrupt */
848			__asm__ __volatile__(
849				".set\tmips3\n\t"
850				"sync\n\t"
851				"wait\n\t"
852				".set\tmips0");
853	end_fill_4785:
854			while (1);
855		}
856		/* Generic clock freq change procedures */
857		else {
858			/* Copy the handler */
859			start = (ulong) &handler;
860			end = (ulong) &afterhandler;
861			dst = KSEG1ADDR(0x180);
862			for (i = 0; i < (end - start); i += 4)
863				*((ulong *)(dst + i)) = *((ulong *)(start + i));
864
865			/* Preload the handler into the cache one line at a time */
866			for (i = 0; i < (end - start); i += ic_lsize)
867				cache_op(dst + i, Fill_I);
868
869			/* Clear BEV bit */
870			MTC0(C0_STATUS, 0, MFC0(C0_STATUS, 0) & ~ST0_BEV);
871
872			/* Enable interrupts */
873			MTC0(C0_STATUS, 0, MFC0(C0_STATUS, 0) | (ALLINTS | ST0_IE));
874
875			/* Enable MIPS timer interrupt */
876			mipsr = sb_setcore(sbh, SB_MIPS33, 0);
877			ASSERT(mipsr);
878			W_REG(osh, &mipsr->intmask, 1);
879
880	start_fill:
881			/* step 1, set clock ratios */
882			MTC0(C0_BROADCOM, 3, te->ratio_parm);
883			MTC0(C0_BROADCOM, 1, te->ratio_cfg);
884
885			/* step 2: program timer intr */
886			W_REG(osh, &mipsr->timer, 100);
887			(void) R_REG(osh, &mipsr->timer);
888
889			/* step 3, switch to async */
890			sync_mode = MFC0(C0_BROADCOM, 4);
891			MTC0(C0_BROADCOM, 4, 1 << 22);
892
893			/* step 4, set cfg active */
894			MTC0(C0_BROADCOM, 2, (1 << 3) | 1);
895
896			/* steps 5 & 6 */
897			__asm__ __volatile__(
898				".set\tmips3\n\t"
899				"wait\n\t"
900				".set\tmips0");
901
902			/* step 7, clear cfg active */
903			MTC0(C0_BROADCOM, 2, 0);
904
905			/* Additional Step: set back to orig sync mode */
906			MTC0(C0_BROADCOM, 4, sync_mode);
907
908			/* step 8, fake soft reset */
909			MTC0(C0_BROADCOM, 5, MFC0(C0_BROADCOM, 5) | (1 << 2));
910
911	end_fill:
912			/* set watchdog timer */
913			W_REG(osh, &cc->watchdog, 20);
914			(void) R_REG(osh, &cc->chipid);
915
916			/* wait for timer interrupt */
917			__asm__ __volatile__(
918				".set\tmips3\n\t"
919				"sync\n\t"
920				"wait\n\t"
921				".set\tmips0");
922			while (1);
923		}
924	}
925
926done:
927	/* Enable 4785 DLL */
928	if (sb_chip(sbh) == BCM4785_CHIP_ID) {
929		uint32 tmp;
930
931		/* set mask to 1e, enable DLL (bit 0) */
932		*dll_ctrl |= 0x0041e021;
933
934		/* enable aggressive hardware mode */
935		*dll_ctrl |= 0x00000080;
936
937		/* wait for lock flag to clear */
938		while ((*dll_ctrl & 0x2) == 0);
939
940		/* clear sticky flags (clear on write 1) */
941		tmp = *dll_ctrl;
942		*dll_ctrl = tmp;
943
944		/* set mask to 5b'10001 */
945		*dll_ctrl = (*dll_ctrl & 0xfffc1fff) | 0x00022000;
946
947		/* enable sync mode */
948		MTC0(C0_BROADCOM, 4, MFC0(C0_BROADCOM, 4) & 0xfe3fffff);
949		(void)MFC0(C0_BROADCOM, 4);
950	}
951
952	/* switch back to previous core */
953	sb_setcoreidx(sbh, idx);
954
955	return ret;
956}
957
958void
959BCMINITFN(enable_pfc)(uint32 mode)
960{
961	ulong start, end;
962	uint ic_size, ic_lsize;
963
964	/* If auto then choose the correct mode for this
965	 * platform, currently we only ever select one mode
966	 */
967	if (mode == PFC_AUTO)
968		mode = PFC_INST;
969
970	icache_probe(MFC0(C0_CONFIG, 1), &ic_size, &ic_lsize);
971
972	/* enable prefetch cache if available */
973	if (MFC0(C0_BROADCOM, 0) & BRCM_PFC_AVAIL) {
974		start = ((ulong) &&setpfc_start) & ~(ic_lsize - 1);
975		end = ((ulong) &&setpfc_end + (ic_lsize - 1)) & ~(ic_lsize - 1);
976
977		/* Preload setpfc code into the cache one line at a time */
978		while (start < end) {
979			cache_op(start, Fill_I);
980			start += ic_lsize;
981		}
982
983		/* Now set the pfc */
984	setpfc_start:
985		/* write range */
986		*(volatile uint32 *)PFC_CR1 = 0xffff0000;
987
988		/* enable */
989		*(volatile uint32 *)PFC_CR0 = mode;
990	setpfc_end:
991		/* Compiler foder */
992		ic_size = 0;
993	}
994}
995
996/* returns the ncdl value to be programmed into sdram_ncdl for calibration */
997uint32
998BCMINITFN(sb_memc_get_ncdl)(sb_t *sbh)
999{
1000	osl_t *osh;
1001	sbmemcregs_t *memc;
1002	uint32 ret = 0;
1003	uint32 config, rd, wr, misc, dqsg, cd, sm, sd;
1004	uint idx, rev;
1005
1006	osh = sb_osh(sbh);
1007
1008	idx = sb_coreidx(sbh);
1009
1010	memc = (sbmemcregs_t *)sb_setcore(sbh, SB_MEMC, 0);
1011	if (memc == 0)
1012		goto out;
1013
1014	rev = sb_corerev(sbh);
1015
1016	config = R_REG(osh, &memc->config);
1017	wr = R_REG(osh, &memc->wrncdlcor);
1018	rd = R_REG(osh, &memc->rdncdlcor);
1019	misc = R_REG(osh, &memc->miscdlyctl);
1020	dqsg = R_REG(osh, &memc->dqsgatencdl);
1021
1022	rd &= MEMC_RDNCDLCOR_RD_MASK;
1023	wr &= MEMC_WRNCDLCOR_WR_MASK;
1024	dqsg &= MEMC_DQSGATENCDL_G_MASK;
1025
1026	if (config & MEMC_CONFIG_DDR) {
1027		ret = (wr << 16) | (rd << 8) | dqsg;
1028	} else {
1029		if (rev > 0)
1030			cd = rd;
1031		else
1032			cd = (rd == MEMC_CD_THRESHOLD) ? rd : (wr + MEMC_CD_THRESHOLD);
1033		sm = (misc & MEMC_MISC_SM_MASK) >> MEMC_MISC_SM_SHIFT;
1034		sd = (misc & MEMC_MISC_SD_MASK) >> MEMC_MISC_SD_SHIFT;
1035		ret = (sm << 16) | (sd << 8) | cd;
1036	}
1037
1038out:
1039	/* switch back to previous core */
1040	sb_setcoreidx(sbh, idx);
1041
1042	return ret;
1043}
1044
1045void
1046hnd_cpu_reset(sb_t *sbh)
1047{
1048	if (sb_chip(sbh) == BCM4785_CHIP_ID)
1049		MTC0(C0_BROADCOM, 4, (1 << 22));
1050	sb_watchdog(sbh, 1);
1051	if (sb_chip(sbh) == BCM4785_CHIP_ID) {
1052		__asm__ __volatile__(
1053			".set\tmips3\n\t"
1054			"sync\n\t"
1055			"wait\n\t"
1056			".set\tmips0");
1057	}
1058	while (1);
1059}
1060
1061#if defined(BCMPERFSTATS)
1062/*
1063 * CP0 Register 25 supports 4 semi-independent 32bit performance counters.
1064 * $25 select 0, 1, 2, and 3 are the counters.  The counters *decrement* (who thought this one up?)
1065 * $25 select 4 and 5 each contain 2-16bit control fields, one for each of the 4 counters
1066 * $25 select 6 is the global perf control register.
1067 */
1068/* enable and start instruction counting */
1069
1070void
1071hndmips_perf_cyclecount_enable(void)
1072{
1073	MTC0(C0_PERFORMANCE, 6, 0x80000200);	/* global enable perf counters */
1074	MTC0(C0_PERFORMANCE, 4,
1075	     0x8048 | MFC0(C0_PERFORMANCE, 4));	/* enable cycles counting for counter 0 */
1076	MTC0(C0_PERFORMANCE, 0, 0);		/* zero counter zero */
1077}
1078
1079void
1080hndmips_perf_instrcount_enable(void)
1081{
1082	MTC0(C0_PERFORMANCE, 6, 0x80000200);	/* global enable perf counters */
1083	MTC0(C0_PERFORMANCE, 4,
1084	     0x8044 | MFC0(C0_PERFORMANCE, 4));	/* enable instructions counting for counter 0 */
1085	MTC0(C0_PERFORMANCE, 0, 0);		/* zero counter zero */
1086}
1087
1088/* enable and start I$ hit and I$ miss counting */
1089void
1090hndmips_perf_icachecount_enable(void)
1091{
1092	MTC0(C0_PERFORMANCE, 6, 0x80000218);	/* enable I$ counting */
1093	MTC0(C0_PERFORMANCE, 4, 0x80148018);	/* count I$ hits in cntr 0 and misses in cntr 1 */
1094	MTC0(C0_PERFORMANCE, 0, 0);		/* zero counter 0 - # I$ hits */
1095	MTC0(C0_PERFORMANCE, 1, 0);		/* zero counter 1 - # I$ misses */
1096}
1097
1098/* enable and start D$ hit and I$ miss counting */
1099void
1100hndmips_perf_dcachecount_enable(void)
1101{
1102	MTC0(C0_PERFORMANCE, 6, 0x80000211);	/* enable D$ counting */
1103	MTC0(C0_PERFORMANCE, 4, 0x80248028);	/* count D$ hits in cntr 0 and misses in cntr 1 */
1104	MTC0(C0_PERFORMANCE, 0, 0);		/* zero counter 0 - # D$ hits */
1105	MTC0(C0_PERFORMANCE, 1, 0);		/* zero counter 1 - # D$ misses */
1106}
1107
1108void
1109hndmips_perf_icache_miss_enable()
1110{
1111	MTC0(C0_PERFORMANCE, 4,
1112	     0x80140000 | MFC0(C0_PERFORMANCE, 4)); /* enable cache misses counting for counter 1 */
1113	MTC0(C0_PERFORMANCE, 1, 0); /* zero counter one */
1114}
1115
1116
1117void
1118hndmips_perf_icache_hit_enable()
1119{
1120	MTC0(C0_PERFORMANCE, 5, 0x8018 | MFC0(C0_PERFORMANCE, 5));
1121	/* enable cache hits counting for counter 2 */
1122	MTC0(C0_PERFORMANCE, 2, 0);		/* zero counter 2 */
1123}
1124
1125uint32
1126hndmips_perf_read_instrcount()
1127{
1128	return -(long)(MFC0(C0_PERFORMANCE, 0));
1129}
1130
1131uint32
1132hndmips_perf_read_cache_miss()
1133{
1134	return -(long)(MFC0(C0_PERFORMANCE, 1));
1135}
1136
1137uint32
1138hndmips_perf_read_cache_hit()
1139{
1140	return -(long)(MFC0(C0_PERFORMANCE, 2));
1141}
1142
1143#endif
1144