1/*
2 * BCM47XX Sonics SiliconBackplane MIPS core routines
3 *
4 * Copyright (C) 2015, Broadcom Corporation. All Rights Reserved.
5 *
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
13 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
15 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
16 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 *
18 * $Id: hndmips.c 419467 2013-08-21 09:19:48Z $
19 */
20
21#include <bcm_cfg.h>
22#include <typedefs.h>
23#include <bcmdefs.h>
24#include <osl.h>
25#include <bcmutils.h>
26#include <siutils.h>
27#include <bcmdevs.h>
28#include <bcmnvram.h>
29#include <hndsoc.h>
30#include <sbchipc.h>
31#include <sbmemc.h>
32#include <mipsinc.h>
33#include <mips33_core.h>
34#include <mips74k_core.h>
35#include <hndcpu.h>
36#include <hndmips.h>
37#include <hndpmu.h>
38#include <dmemc_core.h>
39
40/* debug/trace */
41#ifdef BCMDBG_ERR
42#define	HNDMIPS_ERROR(args)	printf args
43#else
44#define	HNDMIPS_ERROR(args)
45#endif	/* BCMDBG_ERR */
46
47#ifdef BCMDBG
48#define	HNDMIPS_MSG(args)	printf args
49#else
50#define	HNDMIPS_MSG(args)
51#endif	/* BCMDBG */
52#define	HNDMIPS_NONE(args)
53
54/* sbipsflag register format, indexed by irq. */
55static const uint32 sbips_int_mask[] = {
56	0,	/* placeholder */
57	SBIPS_INT1_MASK,
58	SBIPS_INT2_MASK,
59	SBIPS_INT3_MASK,
60	SBIPS_INT4_MASK
61};
62
63static const uint32 sbips_int_shift[] = {
64	0,	/* placeholder */
65	SBIPS_INT1_SHIFT,
66	SBIPS_INT2_SHIFT,
67	SBIPS_INT3_SHIFT,
68	SBIPS_INT4_SHIFT
69};
70
71/*
72 * Map SB cores sharing the MIPS hardware IRQ0 to virtual dedicated OS IRQs.
73 * Per-port BSP code is required to provide necessary translations between
74 * the shared MIPS IRQ and the virtual OS IRQs based on SB core flag.
75 *
76 * See si_irq() for the mapping.
77 */
78static uint shirq_map_base = 0;
79
80/*
81 * Returns the MIPS IRQ assignment of the current core. If unassigned,
82 * 0 is returned.
83 */
84static uint
85si_getirq(si_t *sih)
86{
87	osl_t *osh;
88	uint idx;
89	void *regs;
90	sbconfig_t *sb;
91	uint32 flag, sbipsflag;
92	uint irq = 0;
93
94	osh = si_osh(sih);
95	flag = si_flag(sih);
96
97	idx = si_coreidx(sih);
98
99	if ((regs = si_setcore(sih, MIPS74K_CORE_ID, 0)) != NULL) {
100		/* IntMask1,2,3,4 regs are configured to enable propagation of
101		 * backplane interrupts 0,1,2,3 to mips hw interrupts 1,2,3,4.
102		 */
103		for (irq = 1; irq <= 4; irq++) {
104			if (R_REG(osh, &((mips74kregs_t *)regs)->intmask[irq]) &
105			          (1 << flag))
106				break;
107		}
108	} else if ((regs = si_setcore(sih, MIPS33_CORE_ID, 0)) != NULL) {
109		sb = (sbconfig_t *)((ulong) regs + SBCONFIGOFF);
110
111		/* sbipsflag specifies which core is routed to interrupts 1 to 4 */
112		sbipsflag = R_REG(osh, &sb->sbipsflag);
113		for (irq = 1; irq <= 4; irq++) {
114			if (((sbipsflag & sbips_int_mask[irq]) >>
115			     sbips_int_shift[irq]) == flag)
116				break;
117		}
118	} else {
119		ASSERT("Unknown processor core" == NULL);
120		return 1000;	/* An invalid value */
121	}
122
123	/* If we didn't find it it must be in the shared int (0) */
124	if (irq == 5)
125		irq = 0;
126
127	si_setcoreidx(sih, idx);
128
129	return irq;
130}
131
132/*
133 * Return the MIPS IRQ assignment of the current core. If necessary
134 * map cores sharing the MIPS hw IRQ0 to virtual dedicated OS IRQs.
135 */
136uint
137si_irq(si_t *sih)
138{
139	uint irq = si_getirq(sih);
140	if (irq == 0 && shirq_map_base)
141		irq = si_flag(sih) + shirq_map_base;
142	return irq;
143}
144
145/* Clears the specified MIPS IRQ. */
146static void
147BCMINITFN(si_clearirq)(si_t *sih, uint irq)
148{
149	osl_t *osh;
150	void *regs;
151	sbconfig_t *sb;
152
153	osh = si_osh(sih);
154
155	if ((regs = si_setcore(sih, MIPS74K_CORE_ID, 0)) != NULL) {
156		W_REG(osh, &((mips74kregs_t *)regs)->intmask[irq], 0);
157	} else if ((regs = si_setcore(sih, MIPS33_CORE_ID, 0)) != NULL) {
158		sb = (sbconfig_t *)((ulong) regs + SBCONFIGOFF);
159		if (irq == 0)
160			W_REG(osh, &sb->sbintvec, 0);
161		else
162			OR_REG(osh, &sb->sbipsflag, sbips_int_mask[irq]);
163	} else
164		ASSERT("Unknown processor core" == NULL);
165}
166
167/*
168 * Assigns the specified MIPS IRQ to the specified core. Shared MIPS
169 * IRQ 0 may be assigned more than once.
170 *
171 * The old assignment to the specified core is removed first.
172 */
173static void
174BCMATTACHFN(si_setirq)(si_t *sih, uint irq, uint coreid, uint coreunit)
175{
176	osl_t *osh;
177	void *regs;
178	sbconfig_t *sb;
179	uint32 flag;
180	uint oldirq;
181
182	osh = si_osh(sih);
183
184	regs = si_setcore(sih, coreid, coreunit);
185	ASSERT(regs);
186	flag = si_flag(sih);
187	oldirq = si_getirq(sih);
188	if (oldirq)
189		si_clearirq(sih, oldirq);
190
191	if ((regs = si_setcore(sih, MIPS74K_CORE_ID, 0)) != NULL) {
192		if (!oldirq)
193			AND_REG(osh, &((mips74kregs_t *)regs)->intmask[0], ~(1 << flag));
194
195		if (irq == 0)
196			OR_REG(osh, &((mips74kregs_t *)regs)->intmask[0], 1 << flag);
197		else {
198			W_REG(osh, &((mips74kregs_t *)regs)->intmask[irq], 1 << flag);
199		}
200	} else if ((regs = si_setcore(sih, MIPS33_CORE_ID, 0)) != NULL) {
201		sb = (sbconfig_t *)((ulong) regs + SBCONFIGOFF);
202
203		if (!oldirq)
204			AND_REG(osh, &sb->sbintvec, ~(1 << flag));
205
206		if (irq == 0)
207			OR_REG(osh, &sb->sbintvec, 1 << flag);
208		else {
209			flag <<= sbips_int_shift[irq];
210			ASSERT(!(flag & ~sbips_int_mask[irq]));
211			flag |= R_REG(osh, &sb->sbipsflag) & ~sbips_int_mask[irq];
212			W_REG(osh, &sb->sbipsflag, flag);
213		}
214	} else
215		ASSERT("Unknown processor core" == NULL);
216}
217
218/*
219 * Initializes clocks and interrupts. SB and NVRAM access must be
220 * initialized prior to calling.
221 *
222 * 'shirqmap' enables virtual dedicated OS IRQ mapping if non-zero.
223 */
224void
225BCMATTACHFN(si_mips_init)(si_t *sih, uint shirqmap)
226{
227	osl_t *osh;
228	uint32 c0reg;
229	ulong hz, ns, tmp;
230	chipcregs_t *cc;
231	uint irq;
232
233	osh = si_osh(sih);
234
235	/* Disable interrupts */
236	c0reg = MFC0(C0_STATUS, 0);
237	c0reg &= ~ST0_IE;
238	MTC0(C0_STATUS, 0, c0reg);
239
240	/* Figure out current SB clock speed */
241	if ((hz = si_clock(sih)) == 0)
242		hz = 100000000;
243	ns = 1000000000 / hz;
244
245	/* Setup external interface timing */
246	cc = si_setcoreidx(sih, SI_CC_IDX);
247	ASSERT(cc);
248
249	/* Set timing for the flash */
250	tmp = CEIL(10, ns) << FW_W3_SHIFT;	/* W3 = 10nS */
251	tmp |= CEIL(10, ns) << FW_W1_SHIFT;	/* W1 = 10nS */
252	tmp |= CEIL(120, ns);			/* W0 = 120nS */
253	if (sih->ccrev < 9)
254		W_REG(osh, &cc->flash_waitcount, tmp);
255
256	if ((sih->ccrev < 9) ||
257	    ((CHIPID(sih->chip) == BCM5350_CHIP_ID) && CHIPREV(sih->chiprev) == 0)) {
258		W_REG(osh, &cc->pcmcia_memwait, tmp);
259	}
260
261	/* Save shared IRQ mapping base */
262	shirq_map_base = shirqmap;
263
264	/* Chip specific initialization */
265	switch (CHIPID(sih->chip)) {
266	case BCM5350_CHIP_ID:
267		/* Clear interrupt map */
268		for (irq = 0; irq <= 4; irq++)
269			si_clearirq(sih, irq);
270		si_setirq(sih, 0, CC_CORE_ID, 0);
271		si_setirq(sih, 0, MIPS33_CORE_ID, 0);
272		si_setirq(sih, 1, D11_CORE_ID, 0);
273		si_setirq(sih, 2, ENET_CORE_ID, 0);
274		si_setirq(sih, 3, PCI_CORE_ID, 0);
275		si_setirq(sih, 4, USB_CORE_ID, 0);
276		break;
277	case BCM4785_CHIP_ID:
278		/* Reassign PCI to irq 4 */
279		si_setirq(sih, 4, PCI_CORE_ID, 0);
280		break;
281	case BCM4716_CHIP_ID:
282	case BCM4748_CHIP_ID:
283		/* Clear interrupt map */
284		for (irq = 0; irq <= 4; irq++)
285			si_clearirq(sih, irq);
286		si_setirq(sih, 1, D11_CORE_ID, 0);
287		si_setirq(sih, 2, GMAC_CORE_ID, 0);
288		si_setirq(sih, 3, USB20H_CORE_ID, 0);
289		si_setirq(sih, 4, PCIE_CORE_ID, 0);
290		si_setirq(sih, 0, CC_CORE_ID, 0);
291		si_setirq(sih, 0, I2S_CORE_ID, 0);
292		break;
293	case BCM5356_CHIP_ID:
294	case BCM47162_CHIP_ID:
295	case BCM53572_CHIP_ID:
296		/* Clear interrupt map */
297		for (irq = 0; irq <= 4; irq++)
298			si_clearirq(sih, irq);
299		si_setirq(sih, 1, D11_CORE_ID, 0);
300		si_setirq(sih, 2, GMAC_CORE_ID, 0);
301		si_setirq(sih, 0, CC_CORE_ID, 0);
302		break;
303	case BCM5357_CHIP_ID:
304	case BCM4749_CHIP_ID:
305		/* Clear interrupt map */
306		for (irq = 0; irq <= 4; irq++)
307			si_clearirq(sih, irq);
308		si_setirq(sih, 1, D11_CORE_ID, 0);
309		si_setirq(sih, 2, GMAC_CORE_ID, 0);
310		si_setirq(sih, 3, USB20H_CORE_ID, 0);
311		si_setirq(sih, 0, CC_CORE_ID, 0);
312		si_setirq(sih, 0, I2S_CORE_ID, 0);
313		break;
314	case BCM4706_CHIP_ID:
315		/* Clear interrupt map */
316		for (irq = 0; irq <= 4; irq++)
317			si_clearirq(sih, irq);
318		si_setirq(sih, 1, PCIE_CORE_ID, 0);
319		si_setirq(sih, 2, GMAC_CORE_ID, 0);
320		si_setirq(sih, 3, PCIE_CORE_ID, 1);
321		si_setirq(sih, 4, USB20H_CORE_ID, 0);
322		si_setirq(sih, 0, CC_CORE_ID, 0);
323
324		break;
325	}
326}
327
328/* Do any setup necessary to run a new image and jump to it. */
329void
330hnd_cpu_jumpto(void *addr)
331{
332	void (*jumpto)(void) = addr;
333
334	(jumpto)();
335}
336
337uint32
338BCMINITFN(si_cpu_clock)(si_t *sih)
339{
340	osl_t *osh;
341	chipcregs_t *cc;
342	uint32 n, m;
343	uint idx;
344	uint32 pll_type, rate = 0;
345
346
347	osh = si_osh(sih);
348
349	if (sih->cccaps & CC_CAP_PMU)
350		return si_pmu_cpu_clock(sih, osh);
351
352	/* get index of the current core */
353	idx = si_coreidx(sih);
354
355	/* switch to chipc core */
356	cc = (chipcregs_t *)si_setcoreidx(sih, SI_CC_IDX);
357	ASSERT(cc);
358
359	pll_type = sih->cccaps & CC_CAP_PLL_MASK;
360	n = R_REG(osh, &cc->clockcontrol_n);
361	if ((pll_type == PLL_TYPE2) ||
362	    (pll_type == PLL_TYPE4) ||
363	    (pll_type == PLL_TYPE6) ||
364	    (pll_type == PLL_TYPE7))
365		m = R_REG(osh, &cc->clockcontrol_m3);
366	else if (pll_type == PLL_TYPE5) {
367		rate = 200000000;
368		goto out;
369	} else if (pll_type == PLL_TYPE3) {
370		if (CHIPID(sih->chip) == BCM5365_CHIP_ID) {
371			rate = 200000000;
372			goto out;
373		}
374		/* 5350 uses m2 to control mips */
375		else
376			m = R_REG(osh, &cc->clockcontrol_m2);
377	} else
378		m = R_REG(osh, &cc->clockcontrol_sb);
379
380	/* calculate rate */
381	rate = si_clock_rate(pll_type, n, m);
382
383	if (pll_type == PLL_TYPE6)
384		rate = SB2MIPS_T6(rate);
385
386out:
387	/* switch back to previous core */
388	si_setcoreidx(sih, idx);
389
390	return rate;
391}
392
393uint32
394BCMINITFN(si_mem_clock)(si_t *sih)
395{
396	osl_t *osh;
397
398	osh = si_osh(sih);
399
400	if (sih->cccaps & CC_CAP_PMU)
401		return si_pmu_mem_clock(sih, osh);
402
403	return si_clock(sih);
404}
405
406#define ALLINTS (IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4)
407
408static void __attribute__ ((__noinline__))
409ephy_poll_phyaccess(void)
410{
411	asm("phypoll: \tlui  $8, 0xb800\n\t"
412		"lw   $9, 0x2180($8)\n\t"
413		"lui  $8, 0x4000\n\t"
414		"and $9, $9, $8\n\t"
415		"bnez $9, phypoll\n\t"
416		"nop");
417}
418
419static void __attribute__ ((__noinline__))
420coma_delay(void)
421{
422	/* for (i = 0; i < 3000000; i++); */
423	asm("lui  $8, 0x2d\n\t"
424		"ori     $8,$8,0xc6c0\n\t"
425		"coma_delay_loop: \taddiu   $8,$8,-1\n\t"
426		"bnez    $8,coma_delay_loop\n\t"
427		"nop");
428}
429
430static void __attribute__ ((__noinline__))
431do_router_coma(si_t *sih, void *dmem, int delay)
432{
433	uint8 phy;
434
435	/* set jtag user reg 0 = 0x80 to set DDR pad power saving mode */
436	asm("lui  $8, 0xb800");
437	asm("li   $9, 0xff03ff3a");   /* (16 + addr) << 20 | 0xfe03ff3a */
438	asm("sw   $9, 0x0034($8)");
439	asm("li   $9, 0x80");      /* data */
440	asm("sw   $9, 0x0038($8)");
441	asm("li   $9, 0x80071f1f");
442	asm("sw   $9, 0x0030($8)");
443	asm("sync");
444
445	coma_delay();
446
447	/* ephy ports powerdown */
448
449	/* robo_wreg 0x0 0xf 0x1f 0x2 */
450	asm("lui  $8, 0xb800");
451	asm("li   $9, 0x0090001e");
452	asm("sw   $9, 0x2188($8)");
453	asm("sync");
454	asm("nop");
455	asm("lui  $8, 0xb800");
456	asm("li   $9, 0x701e0001");
457	asm("sw   $9, 0x2180($8)");
458	asm("sync");
459	asm("nop");
460
461	ephy_poll_phyaccess();
462
463	asm("lui  $8, 0xb800");
464	asm("li   $9, 0x0090001e");
465	asm("sw   $9, 0x2188($8)");
466	asm("sync");
467	asm("nop");
468	asm("lui  $8, 0xb800");
469	asm("li   $9, 0x781e001f");
470	asm("sw   $9, 0x2180($8)");
471	asm("sync");
472	asm("nop");
473
474	ephy_poll_phyaccess();
475
476	asm("lui  $8, 0xb800");
477	asm("li   $9, 0x0090001e");
478	asm("sw   $9, 0x2188($8)");
479	asm("sync");
480	asm("nop");
481	asm("lui  $8, 0xb800");
482	asm("li   $9, 0x711e0f01");
483	asm("sw   $9, 0x2180($8)");
484	asm("sync");
485	asm("nop");
486
487	ephy_poll_phyaccess();
488
489	asm("lui  $8, 0xb800");
490	asm("li   $9, 0x0090001e");
491	asm("sw   $9, 0x2188($8)");
492	asm("sync");
493	asm("nop");
494	asm("lui  $8, 0xb800");
495	asm("li   $9, 0x511e0000");
496	asm("sw   $9, 0x2180($8)");
497	asm("sync");
498	asm("nop");
499
500	ephy_poll_phyaccess();
501
502	/* ports 0-5 writes start */
503
504	asm("li  $10, 0");
505
506	for (phy = 0; phy < 5; phy++) {
507
508		asm("sll  $11, $10, 16");
509
510		asm("li   $9, 0x00900000");
511		asm("or   $9, $9, $10");
512		asm("lui  $8, 0xb800");
513		asm("sw   $9, 0x2188($8)");
514		asm("sync");
515		asm("nop");
516		asm("li   $9, 0x7f00008b");
517		asm("or   $9, $9, $11");
518		asm("lui  $8, 0xb800");
519		asm("sw   $9, 0x2180($8)");
520		asm("sync");
521		asm("nop");
522
523		ephy_poll_phyaccess();
524
525		asm("li   $9, 0x00900000");
526		asm("or   $9, $9, $10");
527		asm("lui  $8, 0xb800");
528		asm("sw   $9, 0x2188($8)");
529		asm("sync");
530		asm("nop");
531		asm("li   $9, 0x74006000");
532		asm("or   $9, $9, $11");
533		asm("lui  $8, 0xb800");
534		asm("sw   $9, 0x2180($8)");
535		asm("sync");
536		asm("nop");
537
538		ephy_poll_phyaccess();
539
540		asm("li   $9, 0x00900000");
541		asm("or   $9, $9, $10");
542		asm("lui  $8, 0xb800");
543		asm("sw   $9, 0x2188($8)");
544		asm("sync");
545		asm("nop");
546		asm("li   $9, 0x70000700");
547		asm("or   $9, $9, $11");
548		asm("lui  $8, 0xb800");
549		asm("sw   $9, 0x2180($8)");
550		asm("sync");
551		asm("nop");
552
553		ephy_poll_phyaccess();
554
555		asm("li   $9, 0x00900000");
556		asm("or   $9, $9, $10");
557		asm("lui  $8, 0xb800");
558		asm("sw   $9, 0x2188($8)");
559		asm("sync");
560		asm("nop");
561		asm("li   $9, 0x71001000");
562		asm("or   $9, $9, $11");
563		asm("lui  $8, 0xb800");
564		asm("sw   $9, 0x2180($8)");
565		asm("sync");
566		asm("nop");
567
568		ephy_poll_phyaccess();
569
570		asm("li   $9, 0x00900000");
571		asm("or   $9, $9, $10");
572		asm("lui  $8, 0xb800");
573		asm("sw   $9, 0x2188($8)");
574		asm("sync");
575		asm("nop");
576		asm("li   $9, 0x7f00000b");
577		asm("or   $9, $9, $11");
578		asm("lui  $8, 0xb800");
579		asm("sw   $9, 0x2180($8)");
580		asm("sync");
581		asm("nop");
582
583		ephy_poll_phyaccess();
584
585		asm("addi $10, $10, 1");
586	}
587
588	coma_delay();
589	/* ports 0-5 writes end */
590
591	if (((CHIPID(sih->chip)) == BCM53572_CHIP_ID)) {
592		/* set ephy pll and bias power save through chipc registers */
593		asm("lui  $8, 0xb800");
594		asm("li   $9, 0x4");
595		asm("sw   $9, 0x0650($8)");
596		asm("li   $9, 0x8a60e001");
597		asm("sw   $9, 0x0654($8)");
598		asm("sync");
599		asm("nop");
600
601		coma_delay();
602
603		asm("lui  $8, 0xb800");
604		asm("li   $9, 0x2");
605		asm("sw   $9, 0x0650($8)");
606		asm("li   $9, 0xcad0000f");
607		asm("sw   $9, 0x0654($8)");
608		asm("sync");
609		asm("nop");
610
611		coma_delay();
612
613		/* Clear the dmems ddrctrl reg */
614		asm("lui  $8, 0xb800");
615		asm("li   $9, 0x0");
616		asm("sw   $9, 0x41e4($8)");
617		asm("sync");
618		asm("nop");
619
620		coma_delay();
621	}
622	else {
623		/* A0 vs B0 steps */
624		if (sih->chiprev == 0) {
625
626			/* set jtag user reg 3 = 0x60000 to turn off ephy pll and bias power */
627			asm("lui  $8, 0xb800");
628			asm("li   $9, 0xff33ff3a");   /* (16 + addr) << 20 | 0xfe03ff3a */
629			asm("sw   $9, 0x0034($8)");
630			asm("li   $9, 0x60000");      /* data */
631			asm("sw   $9, 0x0038($8)");
632			asm("li   $9, 0x80071f1f");
633			asm("sw   $9, 0x0030($8)");
634			asm("sync");
635
636			coma_delay();
637		} else {
638
639			/* set ephy pll and bias power power save through chipc registers */
640			asm("lui  $8, 0xb800");
641			asm("li   $9, 0x4");
642			asm("sw   $9, 0x0650($8)");
643			asm("li   $9, 0x8a60e001");
644			asm("sw   $9, 0x0654($8)");
645			asm("sync");
646			asm("nop");
647
648			coma_delay();
649
650			asm("lui  $8, 0xb800");
651			asm("li   $9, 0x2");
652			asm("sw   $9, 0x0650($8)");
653			asm("li   $9, 0xcad0000f");
654			asm("sw   $9, 0x0654($8)");
655			asm("sync");
656			asm("nop");
657
658			coma_delay();
659		}
660	}
661
662	/* set jtag user reg 7 = 0xc0 to turn off the pll and bias power of ephy */
663	asm("lui  $8, 0xb800");
664	asm("li   $9, 0xff73ff3a");
665	asm("sw   $9, 0x0034($8)");
666	asm("li   $9, 0xc0");      /* data */
667	asm("sw   $9, 0x0038($8)");
668	asm("li   $9, 0x80071f1f");
669	asm("sw   $9, 0x0030($8)");
670	asm("sync");
671
672	coma_delay();
673
674	/* set gmac dmp io control = 0 */
675	asm("lui  $8, 0xb810");
676	asm("li   $9, 0x0");
677	asm("sw   $9, 0x2408($8)");
678	asm("sync");
679	asm("nop");
680
681	coma_delay();
682
683	if (((CHIPID(sih->chip)) == BCM53572_CHIP_ID)) {
684		/* set ddr dmp io control = 0 */
685		asm("lui  $8, 0xb810");
686		asm("li   $9, 0x0");
687		asm("sw   $9, 0x4408($8)");
688		asm("sync");
689		asm("nop");
690		/* put dmems in reset */
691		asm("li   $9, 0x1");
692		asm("sw   $9, 0x4800($8)");
693		asm("sync");
694		asm("nop");
695	} else {
696		/* set ddr dmp io control = 0 */
697		asm("lui  $8, 0xb810");
698		asm("li   $9, 0x0");
699		asm("sw   $9, 0x5408($8)");
700		asm("sync");
701		asm("nop");
702		/* put dmemc in reset */
703		asm("li   $9, 0x1");
704		asm("sw   $9, 0x5800($8)");
705		asm("sync");
706		asm("nop");
707	}
708
709	coma_delay();
710
711	/* set PMU control = 1 */
712	asm("lui  $8, 0xb800");
713	asm("li   $9, 0x1");
714	asm("sw   $9, 0x0600($8)");
715	asm("sync");
716	asm("nop");
717
718	coma_delay();
719
720	if (((CHIPID(sih->chip)) != BCM53572_CHIP_ID)) {
721		/* Set switching freq of internal 12V regulator to 600kHz */
722		asm("lui  $8, 0xb800");
723		asm("li   $9, 0x1");
724		asm("sw   $9, 0x0658($8)");
725		asm("sync");
726		asm("nop");
727		asm("lui  $8, 0xb800");
728		asm("li   $9, 0x00018000");
729		asm("sw   $9, 0x065c($8)");
730		asm("sync");
731		asm("nop");
732
733		coma_delay();
734	}
735
736	/* set mips dmp io control = 0 */
737	asm("lui  $8, 0xb810");
738	asm("li   $9, 0x0");
739	asm("sw   $9, 0x3408($8)");
740	asm("sync");
741	asm("nop");
742
743	/* wait for watch dog timer done */
744	__asm__(
745		".set\tmips3\n\t"
746		"sync\n\t"
747		"wait\n\t"
748		".set\tmips0");
749
750	asm("nop");
751	asm("nop");
752}
753
754static void __attribute__ ((__noinline__))
755BCMINITFN(aftercoma)(void)
756{
757
758}
759
760void
761si_router_coma(si_t *sih, int reset, int delay)
762{
763	void *dmem = NULL;
764	chipcregs_t *cc;
765	uint ic_size, ic_lsize;
766	ulong start, end;
767	uint32 c0reg;
768	uint32 tmp;
769	int i;
770	osl_t *osh;
771
772
773	osh = si_osh(sih);
774	/* Disable interrupts */
775
776	c0reg = MFC0(C0_STATUS, 0);
777	tmp = (c0reg & ~(ALLINTS | ST0_IE));
778	MTC0(C0_STATUS, 0, tmp);
779
780	icache_probe(MFC0(C0_CONFIG, 1), &ic_size, &ic_lsize);
781
782	/* Put coma routine into the icache */
783	start = (ulong)&ephy_poll_phyaccess;
784	end = (ulong)&aftercoma;
785	for (i = 0; i < (end - start); i += ic_lsize)
786		cache_op(start + i, Fill_I);
787
788	/* Prepare JTAG registers */
789	si_setcore(sih, CC_CORE_ID, 0);
790	cc = (chipcregs_t *)si_setcoreidx(sih, SI_CC_IDX);
791
792	W_REG(osh, &cc->jtagctrl, 0x01);
793	W_REG(osh, &cc->jtagcmd, 0x80030000);
794	W_REG(osh, &cc->gpioouten, 0x0);
795
796	/* disable gpios */
797	W_REG(osh, &cc->gpioouten, 0x0);
798	W_REG(osh, &cc->chipcontrol_addr, 0x2);
799	W_REG(osh, &cc->chipcontrol_data, 0x04000600);
800
801	/* Set the watchdog */
802	if (((CHIPID(sih->chip)) == BCM5357_CHIP_ID) && (sih->chiprev == 0)) {
803		W_REG(osh, &cc->watchdog, reset*ILP_CLOCK);
804	} else {
805		si_watchdog_ms(sih, reset*1000);
806	}
807
808	if (((CHIPID(sih->chip)) == BCM53572_CHIP_ID))
809		dmem = (void *)si_setcore(sih, DMEMS_CORE_ID, 0);
810	else
811		dmem = (void *)si_setcore(sih, DMEMC_CORE_ID, 0);
812
813	do_router_coma(sih, dmem, delay);
814}
815
816#define PLL_ENTRIES_4706	1
817static bool
818BCMINITFN(mips_pmu_setclock_4706)(si_t *sih, uint32 mipsclock,
819	uint32 ddrclock, uint32 axiclock)
820{
821	chipcregs_t *cc = NULL;
822	osl_t *osh;
823	uint idx, i;
824	bool ret = TRUE, boolChanged = FALSE;
825	/* 25MHz table for 4706 */
826	static uint32 BCMINITDATA(pll25mhz_table)[][3 + PLL_ENTRIES_4706] = {
827	/*	cpu, ddr, axi, proc_PLL,    */
828		{ 200, 100,  50, 0xc0011080, },
829		{ 300, 150,  75, 0xc00110c0, },
830		{ 400, 200, 100, 0xc0011100, },
831		{ 500, 250, 125, 0xc0011140, },
832		{ 600, 300, 150, 0xc0011180, },
833		{ 632, 316, 158, 0xc00157e8, },
834		{ 650, 325, 162, 0xc00111a0, },
835		{ 662, 331, 165, 0xc00111a8, },
836		{0}
837	};
838	static uint32 BCMINITDATA(pll25mhz_table_4706L)[][3 + PLL_ENTRIES_4706] = {
839	/*	cpu, ddr, axi, proc_PLL,    */
840		{ 200, 100,  50, 0xc0011100, },
841		{ 300, 150,  75, 0xc0011180, },
842		{ 400, 200, 100, 0xc0011200, },
843		{0}
844	};
845	uint32 (*pll_table)[4] = pll25mhz_table;
846
847	/* Since we already in 4706 specific routine, we no longer check the chip id
848	 * The 4706L PLL m value is default to 4, thus the n value needs to be doubled
849	 * And since it supports the max frequency is 400MHz, we replace the pll table
850	 * here
851	 */
852	if (sih->chippkg == BCM4706L_PKG_ID) {
853		pll_table = pll25mhz_table_4706L;
854	}
855
856	osh = si_osh(sih);
857
858	/* get index of the current core */
859	idx = si_coreidx(sih);
860
861	/* switch to chipc core */
862	cc = (chipcregs_t *)si_setcoreidx(sih, SI_CC_IDX);
863	ASSERT(cc);
864
865	mipsclock /= 1000000;
866	ddrclock /= 1000000;
867	axiclock /= 1000000;
868
869	for (idx = 0; pll_table[idx][0] != 0; idx++) {
870		if ((mipsclock <= pll_table[idx][0]) &&
871		    ((ddrclock == 0) || (ddrclock <= pll_table[idx][1])) &&
872		    ((axiclock == 0) || (axiclock <= pll_table[idx][2])))
873			break;
874	}
875
876	if (pll_table[idx][0] == 0) {
877		ret = FALSE;
878		goto done;
879	}
880
881	for (i = 0; i < PLL_ENTRIES_4706; i++) {
882		W_REG(osh, &cc->pllcontrol_addr, PMU6_4706_PROCPLL_OFF + i);
883		(void)R_REG(osh, &cc->pllcontrol_addr);
884		if (R_REG(osh, &cc->pllcontrol_data) != pll_table[idx][i + 3]) {
885			W_REG(osh, &cc->pllcontrol_data, pll_table[idx][i + 3]);
886			boolChanged = TRUE;
887		}
888	}
889
890	if (boolChanged == FALSE)
891		goto done;
892
893	/* Wait for the last write */
894	(void)R_REG(osh, &cc->pllcontrol_data);
895
896	/* And now do the pll update */
897	W_REG(osh, &cc->pmucontrol,
898	      R_REG(osh, &cc->pmucontrol) | PCTL_PLL_PLLCTL_UPD);
899
900	__asm__ __volatile__(
901		"nop\n"
902		"nop\n"
903		"nop\n"
904		"nop");
905
906done:
907	si_setcoreidx(sih, idx);
908	return ret;
909}
910
911/*
912 * Set the MIPS, backplane and DDR clocks as closely as possible in chips
913 * with a PMU. So far that means 4716, 47162, 5357, and 5356 all of which share
914 * the same PLL controls.
915 */
916static bool
917BCMINITFN(mips_pmu_setclock)(si_t *sih, uint32 mipsclock, uint32 ddrclock, uint32 axiclock)
918{
919	osl_t *osh;
920	chipcregs_t *cc = NULL;
921	uint idx, i;
922	uint mainpll_pll0 = PMU4716_MAINPLL_PLL0;
923	bool ret = TRUE;
924	uint32 (*pll_table)[8];
925
926	/* 20MHz table for 4716, 4717, 4718, 47162, 5357 */
927	static uint32 BCMINITDATA(pll20mhz_table)[][8] = {
928		/* cpu, ddr, axi, pllctl12,  pllctl13,   pllctl14,   pllctl15,	 pllctl16 */
929		{  66,  66,  66, 0x11100070, 0x00121212, 0x03c00000, 0x20000000, 0x200005c0 },
930		{  75,  75,  75, 0x11100070, 0x00101010, 0x03c00000, 0x20000000, 0x200005c0 },
931		{  80,  80,  80, 0x11100070, 0x000a0a0a, 0x02800000, 0x20000000, 0x200005c0 },
932		{  83,  83,  83, 0x11100070, 0x000c0c0c, 0x03200000, 0x20000000, 0x200005c0 },
933		{ 100,  66,  66, 0x11100070, 0x0012120c, 0x03c00000, 0x30000000, 0x200005c0 },
934		{ 100, 100, 100, 0x11100070, 0x000c0c0c, 0x03c00000, 0x20000000, 0x200005c0 },
935		{ 120,  60,  60, 0x11100070, 0x00101008, 0x03000000, 0x40000000, 0x200005c0 },
936		{ 120, 120, 120, 0x11100070, 0x00080808, 0x03000000, 0x20000000, 0x200005c0 },
937		{ 125,  83,  83, 0x11100070, 0x000c0c08, 0x03200000, 0x30000000, 0x200005c0 },
938		{ 133,  66,  66, 0x11100070, 0x0018180c, 0x05000000, 0x40000000, 0x200005c0 },
939		{ 133, 133, 133, 0x11100070, 0x000c0c0c, 0x05000000, 0x20000000, 0x200005c0 },
940		{ 148, 148,  74, 0x11100070, 0x00120909, 0x04300000, 0x28000000, 0x200005c0 },
941		{ 150,  75,  75, 0x11100070, 0x00101008, 0x03c00000, 0x40000000, 0x200005c0 },
942		{ 150, 100, 100, 0x11100070, 0x000c0c08, 0x03c00000, 0x30000000, 0x200005c0 },
943		{ 150, 150,  75, 0x11100070, 0x00100808, 0x03c00000, 0x28000000, 0x200005c0 },
944		{ 150, 150, 150, 0x11100070, 0x00080808, 0x03c00000, 0x20000000, 0x200005c0 },
945		{ 155, 155,  77, 0x11100070, 0x00120909, 0x04600000, 0x28000000, 0x200005c0 },
946		{ 155, 155, 155, 0x11100070, 0x00090909, 0x04600000, 0x20000000, 0x200005c0 },
947		{ 166,  83,  83, 0x11100070, 0x000c0c06, 0x03200000, 0x40000000, 0x200005c0 },
948		{ 166, 166,  83, 0x11100070, 0x000c0606, 0x03200000, 0x28000000, 0x200005c0 },
949		{ 166, 166, 166, 0x11100070, 0x00060606, 0x03200000, 0x20000000, 0x200005c0 },
950		{ 200, 200, 100, 0x11100070, 0x000c0606, 0x03c00000, 0x28000000, 0x200005c0 },
951		{ 223, 148,  74, 0x11100070, 0x00120906, 0x04300000, 0x38000000, 0x200005c0 },
952		{ 240, 120, 120, 0x11100070, 0x00080804, 0x03000000, 0x40000000, 0x200005c0 },
953		{ 240, 240, 120, 0x11100070, 0x00080404, 0x03000000, 0x28000000, 0x200005c0 },
954		{ 250, 166,  83, 0x11100070, 0x000c0604, 0x03200000, 0x38000000, 0x200005c0 },
955		{ 250, 166, 166, 0x11100070, 0x00060604, 0x03200000, 0x30000000, 0x200005c0 },
956		{ 266, 133, 133, 0x11100070, 0x000c0c06, 0x05000000, 0x40000000, 0x200005c0 },
957		{ 266, 266, 133, 0x11100070, 0x000c0606, 0x05000000, 0x28000000, 0x200005c0 },
958		{ 300, 100, 100, 0x11100070, 0x000c0c04, 0x03c00000, 0x60000000, 0x200005c0 },
959		{ 300, 150,  75, 0x11100070, 0x00100804, 0x03c00000, 0x48000000, 0x200005c0 },
960		{ 300, 150, 150, 0x11100070, 0x00080804, 0x03c00000, 0x40000000, 0x200005c0 },
961		{ 300, 200, 100, 0x11100070, 0x000c0604, 0x03c00000, 0x38000000, 0x200005c0 },
962		{ 320, 160,  80, 0x11100070, 0x00100804, 0x04000000, 0x48000000, 0x200005c0 },
963		{ 320, 213, 106, 0x11100070, 0x000c0604, 0x04000000, 0x38000000, 0x200005c0 },
964		{ 320, 240, 120, 0x11100070, 0x00080403, 0x03000000, 0x38000000, 0x200005c0 },
965		{ 320, 256, 128, 0x11100070, 0x000a0504, 0x04000000, 0x38000000, 0x200005c0 },
966		{ 330, 165,  82, 0x11100070, 0x00100804, 0x04200000, 0x48000000, 0x200005c0 },
967		{ 330, 165, 165, 0x11100070, 0x00080804, 0x04200000, 0x40000000, 0x200005c0 },
968		{ 333, 166,  83, 0x11100070, 0x000c0603, 0x03200000, 0x48000000, 0x200005c0 },
969		{ 333, 166, 166, 0x11100070, 0x00060603, 0x03200000, 0x40000000, 0x200005c0 },
970		{ 340, 226, 113, 0x11100070, 0x000c0604, 0x04400000, 0x38000000, 0x200005c0 },
971		{ 350, 175,  87, 0x11100070, 0x00100804, 0x04600000, 0x48000000, 0x200005c0 },
972		{ 353, 176,  88, 0x11100070, 0x000c0603, 0x03500000, 0x48000000, 0x200005c0 },
973		{ 360, 240, 120, 0x11100070, 0x000c0604, 0x04800000, 0x38000000, 0x200005c0 },
974		{ 370, 185,  92, 0x11100070, 0x00100804, 0x04a00000, 0x48000000, 0x200005c0 },
975		{ 370, 246, 123, 0x11100070, 0x000c0604, 0x04a00000, 0x38000000, 0x200005c0 },
976		{ 373, 186,  93, 0x11100070, 0x000c0603, 0x03800000, 0x48000000, 0x200005c0 },
977		{ 400, 133, 133, 0x11100070, 0x000c0c04, 0x05000000, 0x60000000, 0x200005c0 },
978		{ 400, 160,  80, 0x11100070, 0x00140a04, 0x05000000, 0x58000000, 0x200005c0 },
979		{ 400, 160, 160, 0x11100070, 0x000a0a04, 0x05000000, 0x50000000, 0x200005c0 },
980		{ 400, 200, 100, 0x11100070, 0x00100804, 0x05000000, 0x48000000, 0x200005c0 },
981		{ 400, 266, 133, 0x11100070, 0x000c0604, 0x05000000, 0x38000000, 0x200005c0 },
982		{ 426, 213, 106, 0x11100070, 0x000c0603, 0x04000000, 0x48000000, 0x200005c0 },
983		{ 440, 220, 110, 0x11100070, 0x000c0603, 0x04200000, 0x48000000, 0x200005c0 },
984		{ 446, 148,  74, 0x11100070, 0x00120903, 0x04300000, 0x68000000, 0x200005c0 },
985		{ 453, 226, 113, 0x11100070, 0x000c0603, 0x04400000, 0x48000000, 0x200005c0 },
986		{ 466, 233, 116, 0x11100070, 0x000c0603, 0x04600000, 0x48000000, 0x200005c0 },
987		{ 480, 137,  68, 0x11100070, 0x000e0702, 0x03000000, 0x78000000, 0x200005c0 },
988		{ 480, 137, 137, 0x11100070, 0x00070702, 0x03000000, 0x70000000, 0x200005c0 },
989		{ 480, 160,  80, 0x11100070, 0x000c0602, 0x03000000, 0x68000000, 0x200005c0 },
990		{ 480, 240, 120, 0x11100070, 0x00080402, 0x03000000, 0x48000000, 0x200005c0 },
991		{ 500, 100, 100, 0x11100070, 0x000a0a02, 0x03200000, 0xa0000000, 0x200005c0 },
992		{ 500, 166,  83, 0x11100070, 0x000c0602, 0x03200000, 0x68000000, 0x200005c0 },
993		{ 500, 166, 166, 0x11100070, 0x00060602, 0x03200000, 0x60000000, 0x200005c0 },
994		{ 500, 200, 100, 0x11100070, 0x000a0502, 0x03200000, 0x58000000, 0x200005c0 },
995		{ 500, 250, 125, 0x11100070, 0x00080402, 0x03200000, 0x48000000, 0x200005c0 },
996		{ 530, 176,  88, 0x11100070, 0x000c0602, 0x03500000, 0x68000000, 0x200005c0 },
997		{ 530, 176, 176, 0x11100070, 0x00060602, 0x03500000, 0x60000000, 0x200005c0 },
998		{ 530, 212, 106, 0x11100070, 0x000a0502, 0x03500000, 0x58000000, 0x200005c0 },
999		{ 530, 265, 132, 0x11100070, 0x00080402, 0x03500000, 0x48000000, 0x200005c0 },
1000		{ 533, 133, 133, 0x11100070, 0x000c0c03, 0x05000000, 0x80000000, 0x200005c0 },
1001		{ 533, 266, 133, 0x11100070, 0x000c0603, 0x05000000, 0x48000000, 0x200005c0 },
1002		{0}
1003	};
1004
1005	/* 25MHz table for 5356 */
1006	static uint32 BCMINITDATA(pll25mhz_table)[][8] = {
1007		/* cpu, ddr, axi, pllctl12,  pllctl13,   pllctl14,   pllctl15,   pllctl16 */
1008		{  66,  66,  66, 0x11100070, 0x00121212, 0x03000000, 0x20000000, 0x200005c0 },
1009		{  75,  75,  75, 0x11100070, 0x00101010, 0x03000000, 0x20000000, 0x200005c0 },
1010		{  80,  80,  80, 0x11100070, 0x000a0a0a, 0x02000000, 0x20000000, 0x200005c0 },
1011		{  83,  83,  83, 0x11100070, 0x000c0c0c, 0x02800000, 0x20000000, 0x200005c0 },
1012		{ 100,  66,  66, 0x11100070, 0x0012120c, 0x03000000, 0x30000000, 0x200005c0 },
1013		{ 100, 100, 100, 0x11100070, 0x000c0c0c, 0x03000000, 0x20000000, 0x200005c0 },
1014		{ 125,  83,  83, 0x11100070, 0x000c0c08, 0x02800000, 0x30000000, 0x200005c0 },
1015		{ 133, 133, 133, 0x11100070, 0x000c0c0c, 0x04000000, 0x20000000, 0x200005c0 },
1016		{ 150,  75,  75, 0x11100070, 0x00101008, 0x03000000, 0x40000000, 0x200005c0 },
1017		{ 150, 100, 100, 0x11100070, 0x000c0c08, 0x03000000, 0x30000000, 0x200005c0 },
1018		{ 150, 150,  75, 0x11100070, 0x00100808, 0x03000000, 0x28000000, 0x200005c0 },
1019		{ 150, 150, 150, 0x11100070, 0x00080808, 0x03000000, 0x20000000, 0x200005c0 },
1020		{ 166,  83,  83, 0x11100070, 0x000c0c06, 0x02800000, 0x40000000, 0x200005c0 },
1021		{ 166, 166,  83, 0x11100070, 0x000c0606, 0x02800000, 0x28000000, 0x200005c0 },
1022		{ 166, 166, 166, 0x11100070, 0x00060606, 0x02800000, 0x20000000, 0x200005c0 },
1023		{ 200, 133, 133, 0x11100070, 0x000c0c08, 0x04000000, 0x30000000, 0x200005c0 },
1024		{ 200, 200, 100, 0x11100070, 0x000c0606, 0x03000000, 0x28000000, 0x200005c0 },
1025		{ 250, 166,  83, 0x11100070, 0x000c0604, 0x02800000, 0x38000000, 0x200005c0 },
1026		{ 250, 166, 166, 0x11100070, 0x00060604, 0x02800000, 0x30000000, 0x200005c0 },
1027		{ 293, 195,  97, 0x11100070, 0x000c0604, 0x02f00000, 0x38000000, 0x200005c0 },
1028		{ 300, 100, 100, 0x11100070, 0x000c0c04, 0x03000000, 0x60000000, 0x200005c0 },
1029		{ 300, 120, 120, 0x11100070, 0x000a0a04, 0x03000000, 0x50000000, 0x200005c0 },
1030		{ 300, 150,  75, 0x11100070, 0x00100804, 0x03000000, 0x48000000, 0x200005c0 },
1031		{ 300, 150, 150, 0x11100070, 0x00080804, 0x03000000, 0x40000000, 0x200005c0 },
1032		{ 300, 200, 100, 0x11100070, 0x000c0604, 0x03000000, 0x38000000, 0x200005c0 },
1033		{ 332, 110, 110, 0x11100070, 0x000c0c04, 0x03540000, 0x6047ae14, 0x202c2820 },
1034		{ 332, 133, 133, 0x11100070, 0x000a0a04, 0x03540000, 0x5047ae14, 0x202c2820 },
1035		{ 332, 166,  83, 0x11100070, 0x00100804, 0x03540000, 0x4847ae14, 0x202c2820 },
1036		{ 333, 111, 111, 0x11100070, 0x00090903, 0x02800000, 0x60000000, 0x200005c0 },
1037		{ 333, 133, 133, 0x11100070, 0x000f0f06, 0x05000000, 0x50000000, 0x38000700 },
1038		{ 333, 166,  83, 0x11100070, 0x000c0603, 0x02800000, 0x48000000, 0x200005c0 },
1039		{ 333, 166, 166, 0x11100070, 0x00060603, 0x02800000, 0x40000000, 0x200005c0 },
1040		{ 400, 133, 133, 0x11100070, 0x000c0c04, 0x04000000, 0x60000000, 0x200005c0 },
1041		{ 400, 200, 100, 0x11100070, 0x000c0603, 0x03000000, 0x48000000, 0x200005c0 },
1042		{ 400, 266, 133, 0x11100070, 0x000c0604, 0x04000000, 0x38000000, 0x200005c0 },
1043		{ 500, 166,  83, 0x11100070, 0x000c0602, 0x02800000, 0x68000000, 0x200005c0 },
1044		{ 500, 166, 166, 0x11100070, 0x00060602, 0x02800000, 0x60000000, 0x200005c0 },
1045		{ 500, 200, 100, 0x11100070, 0x000a0502, 0x02800000, 0x58000000, 0x200005c0 },
1046		{ 500, 250, 125, 0x11100070, 0x00080402, 0x02800000, 0x48000000, 0x200005c0 },
1047		{0}
1048	};
1049
1050	if (CHIPID(sih->chip) == BCM4706_CHIP_ID)
1051		return mips_pmu_setclock_4706(sih, mipsclock, ddrclock, axiclock);
1052
1053	/* By default use the 20MHz pll table */
1054	pll_table = pll20mhz_table;
1055
1056	osh = si_osh(sih);
1057
1058	/* Adjust the mainpll_pll0 address and pll table for 5356 */
1059	if (CHIPID(sih->chip) == BCM5356_CHIP_ID) {
1060	  mainpll_pll0 = PMU5356_MAINPLL_PLL0;
1061	  pll_table = pll25mhz_table;
1062	}
1063	/* Adjust the mainpll_pll0 address and pll table for 5357 */
1064	if ((CHIPID(sih->chip) == BCM5357_CHIP_ID) ||
1065		(CHIPID(sih->chip) == BCM4749_CHIP_ID)) {
1066	  mainpll_pll0 = PMU5357_MAINPLL_PLL0;
1067	  pll_table = pll20mhz_table;
1068	}
1069
1070	/* get index of the current core */
1071	idx = si_coreidx(sih);
1072
1073	/* switch to chipc core */
1074	cc = (chipcregs_t *)si_setcoreidx(sih, SI_CC_IDX);
1075	ASSERT(cc);
1076
1077	mipsclock /= 1000000;
1078	ddrclock /= 1000000;
1079	axiclock /= 1000000;
1080
1081	HNDMIPS_NONE(("Looking for %d/%d/%d\n", mipsclock, ddrclock, axiclock));
1082
1083	for (idx = 0; pll_table[idx][0] != 0; idx++) {
1084		uint16 chippkg;
1085		/* Bypass pll entries that are not allowed */
1086		if ((((pll_table[idx][4] & 0xff) < 4) ||
1087		     (((pll_table[idx][5] >> 20) & 0x1ff) > 0x50)) &&
1088		    ((CHIPID(sih->chip) == BCM5357_CHIP_ID) ||
1089		    (CHIPID(sih->chip) == BCM4749_CHIP_ID)) &&
1090		    (((chippkg = R_REG(osh, &cc->sromotp[23])) & 0x80) == 0x80)) {
1091			continue;
1092		}
1093		if ((mipsclock <= pll_table[idx][0]) &&
1094		    ((ddrclock == 0) || (ddrclock <= pll_table[idx][1])) &&
1095		    ((axiclock == 0) || (axiclock <= pll_table[idx][2])))
1096			break;
1097	}
1098
1099	if (pll_table[idx][0] == 0) {
1100		ret = FALSE;
1101		goto done;
1102	}
1103
1104	HNDMIPS_NONE(("Using entry %d: %d/%d/%d, 0x%08x, 0x%08x, 0x%08x, 0x%08x, %d\n", idx,
1105	              pll_table[idx][0], pll_table[idx][1], pll_table[idx][2],
1106	              pll_table[idx][3], pll_table[idx][4], pll_table[idx][5],
1107	              pll_table[idx][6], pll_table[idx][7]));
1108
1109	for (i = PMU5_PLL_P1P2_OFF; i <= PMU5_PLL_FMAB_OFF; i++) {
1110		W_REG(osh, &cc->pllcontrol_addr, mainpll_pll0 + i);
1111		(void)R_REG(osh, &cc->pllcontrol_addr);
1112		if (R_REG(osh, &cc->pllcontrol_data) != pll_table[idx][i + 3])
1113			break;
1114	}
1115
1116	/* All matched, no change needed */
1117	if (i == (PMU5_PLL_FMAB_OFF + 1))
1118		goto done;
1119
1120	/* Write new PLL settings */
1121	for (i = PMU5_PLL_P1P2_OFF; i <= PMU5_PLL_PLLCTL_OFF; i++) {
1122		uint32 tmp;
1123
1124		W_REG(osh, &cc->pllcontrol_addr, mainpll_pll0 + i);
1125		(void)R_REG(osh, &cc->pllcontrol_addr);
1126		tmp = pll_table[idx][i + 3];
1127		W_REG(osh, &cc->pllcontrol_data, tmp);
1128	}
1129	/* Wait for the last write */
1130	(void)R_REG(osh, &cc->pllcontrol_data);
1131
1132	if (CHIPID(sih->chip) == BCM47162_CHIP_ID) {
1133		/* In 47162, clear min_res_mask */
1134		W_REG(osh, &cc->min_res_mask,
1135		      R_REG(osh, &cc->min_res_mask) & ~RES4716_PROC_HT_AVAIL);
1136
1137		/* Reset, use chipcommon's watchdog, not the PMU */
1138		W_REG(osh, &cc->watchdog, 1000);
1139
1140		/* And now do the pll update */
1141		W_REG(osh, &cc->pmucontrol,
1142		      R_REG(osh, &cc->pmucontrol) | PCTL_PLL_PLLCTL_UPD);
1143	} else
1144		si_watchdog(sih, 100);
1145
1146	/* wait for timer interrupt */
1147	while (1)
1148		__asm__ __volatile__(
1149			".set\tmips3\n\t"
1150			"sync\n\t"
1151			"wait\n\t"
1152			".set\tmips0");
1153
1154done:
1155	/* switch back to previous core */
1156	si_setcoreidx(sih, idx);
1157
1158	return ret;
1159}
1160
1161static void
1162BCMINITFN(handler)(void)
1163{
1164	__asm__(
1165		".set\tmips32\n\t"
1166		"ssnop\n\t"
1167		"ssnop\n\t"
1168	/* Disable interrupts */
1169	/*	MTC0(C0_STATUS, 0, MFC0(C0_STATUS, 0) & ~(ALLINTS | STO_IE)); */
1170		"mfc0 $15, $12\n\t"
1171	/* Just a Hack to not to use reg 'at' which was causing problems on 4704 A2 */
1172		"li $14, -31746\n\t"
1173		"and $15, $15, $14\n\t"
1174		"mtc0 $15, $12\n\t"
1175		"eret\n\t"
1176		"nop\n\t"
1177		"nop\n\t"
1178		".set\tmips0");
1179}
1180
1181/* The following MUST come right after handler() */
1182static void
1183BCMINITFN(afterhandler)(void)
1184{
1185}
1186
1187/*
1188 * Set the MIPS, backplane and PCI clocks as closely as possible.
1189 *
1190 * MIPS clocks synchronization function has been moved from PLL in chipcommon
1191 * core rev. 15 to a DLL inside the MIPS core in 4785.
1192 */
1193bool
1194BCMINITFN(si_mips_setclock)(si_t *sih, uint32 mipsclock, uint32 siclock, uint32 pciclock)
1195{
1196	osl_t *osh;
1197	chipcregs_t *cc = NULL;
1198	mips33regs_t *mipsr = NULL;
1199	volatile uint32 *clockcontrol_n, *clockcontrol_sb, *clockcontrol_pci, *clockcontrol_m2;
1200	uint32 orig_n, orig_sb, orig_pci, orig_m2, orig_mips, orig_ratio_parm, orig_ratio_cfg;
1201	uint32 pll_type, sync_mode;
1202	uint ic_size, ic_lsize;
1203	uint idx, i;
1204
1205	/* PLL configuration: type 3 */
1206	typedef struct {
1207		uint32 mipsclock;
1208		uint16 n;
1209		uint32 m2; /* that is the clockcontrol_m2 */
1210	} type3_table_t;
1211	static type3_table_t type3_table[] = {
1212		/* for 5350, mips clock is always double sb clock */
1213		{ 150000000, 0x311, 0x4020005 },
1214		{ 200000000, 0x311, 0x4020003 },
1215		};
1216
1217	/* PLL configuration: type 2, 4, 7 */
1218	typedef struct {
1219		uint32 mipsclock;
1220		uint32 sbclock;
1221		uint32 pciclock;
1222		uint16 n;
1223		uint32 sb;
1224		uint32 pci33;
1225		uint32 m2;
1226		uint32 m3;
1227		uint32 ratio_cfg;
1228		uint32 ratio_parm;
1229		uint32 dll_r1;
1230		uint32 dll_r2;
1231	} n4m_table_t;
1232	static n4m_table_t BCMINITDATA(type2_table)[] = {
1233		{ 120000000, 60000000, 32000000, 0x0303, 0x01000200, 0x01000600, 0x01000200,
1234		0x05000200, 11, 0x0aaa0555, 8 /* ratio  4/8 */, 0x00aa0055 },
1235		{ 150000000, 75000000, 33333333, 0x0303, 0x01000100, 0x01000600, 0x01000100,
1236		0x05000100, 11, 0x0aaa0555, 8 /* ratio  4/8 */, 0x00aa0055 },
1237		{ 180000000, 80000000, 30000000, 0x0403, 0x01010000, 0x01020300, 0x01020600,
1238		0x05000100, 8, 0x012a00a9, 9 /* ratio  4/9 */, 0x012a00a9 },
1239		{ 180000000, 90000000, 30000000, 0x0403, 0x01000100, 0x01020300, 0x01000100,
1240		0x05000100, 11, 0x0aaa0555, 8 /* ratio  4/8 */, 0x00aa0055 },
1241		{ 200000000, 100000000, 33333333, 0x0303, 0x02010000, 0x02040001, 0x02010000,
1242		0x06000001, 11, 0x0aaa0555, 8 /* ratio  4/8 */, 0x00aa0055 },
1243		{ 211200000, 105600000, 30171428, 0x0902, 0x01000200, 0x01030400, 0x01000200,
1244		0x05000200, 11, 0x0aaa0555, 8 /* ratio  4/8 */, 0x00aa0055 },
1245		{ 220800000, 110400000, 31542857, 0x1500, 0x01000200, 0x01030400, 0x01000200,
1246		0x05000200, 11, 0x0aaa0555, 8 /* ratio  4/8 */, 0x00aa0055 },
1247		{ 230400000, 115200000, 32000000, 0x0604, 0x01000200, 0x01020600, 0x01000200,
1248		0x05000200, 11, 0x0aaa0555, 8 /* ratio  4/8 */, 0x00aa0055 },
1249		{ 234000000, 104000000, 31200000, 0x0b01, 0x01010000, 0x01010700, 0x01020600,
1250		0x05000100, 8, 0x012a00a9, 9 /* ratio  4/9 */, 0x012a00a9 },
1251		{ 240000000, 120000000, 33333333, 0x0803, 0x01000200, 0x01020600, 0x01000200,
1252		0x05000200, 11, 0x0aaa0555, 8 /* ratio  4/8 */, 0x00aa0055 },
1253		{ 252000000, 126000000, 33333333, 0x0504, 0x01000100, 0x01020500, 0x01000100,
1254		0x05000100, 11, 0x0aaa0555, 8 /* ratio  4/8 */, 0x00aa0055 },
1255		{ 264000000, 132000000, 33000000, 0x0903, 0x01000200, 0x01020700, 0x01000200,
1256		0x05000200, 11, 0x0aaa0555, 8 /* ratio  4/8 */, 0x00aa0055 },
1257		{ 270000000, 120000000, 30000000, 0x0703, 0x01010000, 0x01030400, 0x01020600,
1258		0x05000100, 8, 0x012a00a9, 9 /* ratio  4/9 */, 0x012a00a9 },
1259		{ 276000000, 122666666, 31542857, 0x1500, 0x01010000, 0x01030400, 0x01020600,
1260		0x05000100, 8, 0x012a00a9, 9 /* ratio  4/9 */, 0x012a00a9 },
1261		{ 280000000, 140000000, 31111111, 0x0503, 0x01000000, 0x01010600, 0x01000000,
1262		0x05000000, 11, 0x0aaa0555, 8 /* ratio  4/8 */, 0x00aa0055 },
1263		{ 288000000, 128000000, 32914285, 0x0604, 0x01010000, 0x01030400, 0x01020600,
1264		0x05000100, 8, 0x012a00a9, 9 /* ratio  4/9 */, 0x012a00a9 },
1265		{ 288000000, 144000000, 32000000, 0x0404, 0x01000000, 0x01010600, 0x01000000,
1266		0x05000000, 11, 0x0aaa0555, 8 /* ratio  4/8 */, 0x00aa0055 },
1267		{ 300000000, 133333333, 33333333, 0x0803, 0x01010000, 0x01020600, 0x01010100,
1268		0x05000100, 8, 0x012a00a9, 9 /* ratio  4/9 */, 0x012a00a9 },
1269		{ 300000000, 133333333, 37500000, 0x0803, 0x01010000, 0x01020500, 0x01010100,
1270		0x05000100, 8, 0x012a00a9, 9 /* ratio  4/9 */, 0x012a00a9 },
1271		{ 300000000, 133333333, 42857142, 0x0803, 0x01010000, 0x01020400, 0x01010100,
1272		0x05000100, 8, 0x012a00a9, 9 /* ratio  4/9 */, 0x012a00a9 },
1273		{ 300000000, 133333333, 50000000, 0x0803, 0x01010000, 0x01020300, 0x01010100,
1274		0x05000100, 8, 0x012a00a9, 9 /* ratio  4/9 */, 0x012a00a9 },
1275		{ 300000000, 133333333, 60000000, 0x0803, 0x01010000, 0x01020200, 0x01010100,
1276		0x05000100, 8, 0x012a00a9, 9 /* ratio  4/9 */, 0x012a00a9 },
1277		{ 300000000, 150000000, 33333333, 0x0803, 0x01000100, 0x01020600, 0x01010100,
1278		0x05000100, 11, 0x0aaa0555, 8 /* ratio  4/8 */, 0x00aa0055 },
1279		{ 300000000, 150000000, 37500000, 0x0803, 0x01000100, 0x01020500, 0x01010100,
1280		0x05000100, 11, 0x0aaa0555, 8 /* ratio  4/8 */, 0x00aa0055 },
1281		{ 300000000, 150000000, 42857142, 0x0803, 0x01000100, 0x01020400, 0x01010100,
1282		0x05000100, 11, 0x0aaa0555, 8 /* ratio  4/8 */, 0x00aa0055 },
1283		{ 300000000, 150000000, 50000000, 0x0803, 0x01000100, 0x01020300, 0x01010100,
1284		0x05000100, 11, 0x0aaa0555, 8 /* ratio  4/8 */, 0x00aa0055 },
1285		{ 300000000, 150000000, 60000000, 0x0803, 0x01000100, 0x01020200, 0x01010100,
1286		0x05000100, 11, 0x0aaa0555, 8 /* ratio  4/8 */, 0x00aa0055 },
1287		{ 330000000, 132000000, 33000000, 0x0903, 0x01000200, 0x00020200, 0x01010100,
1288		0x05000100, 0, 0, 10 /* ratio 4/10 */, 0x02520129 },
1289		{ 330000000, 146666666, 33000000, 0x0903, 0x01010000, 0x00020200, 0x01010100,
1290		0x05000100, 0, 0, 9 /* ratio 4/9 */, 0x012a00a9 },
1291		{ 330000000, 165000000, 33000000, 0x0903, 0x01000100, 0x00020200, 0x01010100,
1292		0x05000100, 0, 0, 8 /* ratio 4/8 */, 0x00aa0055 },
1293		{ 330000000, 165000000, 41250000, 0x0903, 0x01000100, 0x00020100, 0x01010100,
1294		0x05000100, 0, 0, 8 /* ratio 4/8 */, 0x00aa0055 },
1295		{ 330000000, 165000000, 55000000, 0x0903, 0x01000100, 0x00020000, 0x01010100,
1296		0x05000100, 0, 0, 8 /* ratio 4/8 */, 0x00aa0055 },
1297		{ 360000000, 120000000, 32000000, 0x0a03, 0x01000300, 0x00010201, 0x01010200,
1298		0x05000100, 0, 0, 12 /* ratio 4/12 */, 0x04920492 },
1299		{ 360000000, 144000000, 32000000, 0x0a03, 0x01000200, 0x00010201, 0x01010200,
1300		0x05000100, 0, 0, 10 /* ratio 4/10 */, 0x02520129 },
1301		{ 360000000, 160000000, 32000000, 0x0a03, 0x01010000, 0x00010201, 0x01010200,
1302		0x05000100, 0, 0, 9 /* ratio 4/9 */, 0x012a00a9 },
1303		{ 360000000, 180000000, 32000000, 0x0a03, 0x01000100, 0x00010201, 0x01010200,
1304		0x05000100, 0, 0, 8 /* ratio 4/8 */, 0x00aa0055 },
1305		{ 360000000, 180000000, 40000000, 0x0a03, 0x01000100, 0x00010101, 0x01010200,
1306		0x05000100, 0, 0, 8 /* ratio 4/8 */, 0x00aa0055 },
1307		{ 360000000, 180000000, 53333333, 0x0a03, 0x01000100, 0x00010001, 0x01010200,
1308		0x05000100, 0, 0, 8 /* ratio 4/8 */, 0x00aa0055 },
1309		{ 390000000, 130000000, 32500000, 0x0b03, 0x01010100, 0x00020101, 0x01020100,
1310		0x05000100, 0, 0, 12 /* ratio 4/12 */, 0x04920492 },
1311		{ 390000000, 156000000, 32500000, 0x0b03, 0x01000200, 0x00020101, 0x01020100,
1312		0x05000100, 0, 0, 10 /* ratio 4/10 */, 0x02520129 },
1313		{ 390000000, 173000000, 32500000, 0x0b03, 0x01010000, 0x00020101, 0x01020100,
1314		0x05000100, 0, 0, 9 /* ratio 4/9 */, 0x012a00a9 },
1315		{ 390000000, 195000000, 32500000, 0x0b03, 0x01000100, 0x00020101, 0x01020100,
1316		0x05000100, 0, 0, 8 /* ratio 4/8 */, 0x00aa0055 },
1317	};
1318	static n4m_table_t BCMINITDATA(type4_table)[] = {
1319		{ 120000000, 60000000, 0, 0x0009, 0x11020009, 0x01030203, 0x11020009, 0x04000009,
1320		11, 0x0aaa0555 },
1321		{ 150000000, 75000000, 0, 0x0009, 0x11050002, 0x01030203, 0x11050002, 0x04000005,
1322		11, 0x0aaa0555 },
1323		{ 192000000, 96000000, 0, 0x0702, 0x04000011, 0x11030011, 0x04000011, 0x04000003,
1324		11, 0x0aaa0555 },
1325		{ 198000000, 99000000, 0, 0x0603, 0x11020005, 0x11030011, 0x11020005, 0x04000005,
1326		11, 0x0aaa0555 },
1327		{ 200000000, 100000000, 0, 0x0009, 0x04020011, 0x11030011, 0x04020011, 0x04020003,
1328		11, 0x0aaa0555 },
1329		{ 204000000, 102000000, 0, 0x0c02, 0x11020005, 0x01030303, 0x11020005, 0x04000005,
1330		11, 0x0aaa0555 },
1331		{ 208000000, 104000000, 0, 0x0802, 0x11030002, 0x11090005, 0x11030002, 0x04000003,
1332		11, 0x0aaa0555 },
1333		{ 210000000, 105000000, 0, 0x0209, 0x11020005, 0x01030303, 0x11020005, 0x04000005,
1334		11, 0x0aaa0555 },
1335		{ 216000000, 108000000, 0, 0x0111, 0x11020005, 0x01030303, 0x11020005, 0x04000005,
1336		11, 0x0aaa0555 },
1337		{ 224000000, 112000000, 0, 0x0205, 0x11030002, 0x02002103, 0x11030002, 0x04000003,
1338		11, 0x0aaa0555 },
1339		{ 228000000, 101333333, 0, 0x0e02, 0x11030003, 0x11210005, 0x01030305, 0x04000005,
1340		8, 0x012a00a9 },
1341		{ 228000000, 114000000, 0, 0x0e02, 0x11020005, 0x11210005, 0x11020005, 0x04000005,
1342		11, 0x0aaa0555 },
1343		{ 240000000, 102857143, 0, 0x0109, 0x04000021, 0x01050203, 0x11030021, 0x04000003,
1344		13, 0x254a14a9 },
1345		{ 240000000, 120000000, 0, 0x0109, 0x11030002, 0x01050203, 0x11030002, 0x04000003,
1346		11, 0x0aaa0555 },
1347		{ 252000000, 100800000, 0, 0x0203, 0x04000009, 0x11050005, 0x02000209, 0x04000002,
1348		9, 0x02520129 },
1349		{ 252000000, 126000000, 0, 0x0203, 0x04000005, 0x11050005, 0x04000005, 0x04000002,
1350		11, 0x0aaa0555 },
1351		{ 264000000, 132000000, 0, 0x0602, 0x04000005, 0x11050005, 0x04000005, 0x04000002,
1352		11, 0x0aaa0555 },
1353		{ 272000000, 116571428, 0, 0x0c02, 0x04000021, 0x02000909, 0x02000221, 0x04000003,
1354		13, 0x254a14a9 },
1355		{ 280000000, 120000000, 0, 0x0209, 0x04000021, 0x01030303, 0x02000221, 0x04000003,
1356		13, 0x254a14a9 },
1357		{ 288000000, 123428571, 0, 0x0111, 0x04000021, 0x01030303, 0x02000221, 0x04000003,
1358		13, 0x254a14a9 },
1359		{ 300000000, 120000000, 0, 0x0009, 0x04000009, 0x01030203, 0x02000902, 0x04000002,
1360		9, 0x02520129 },
1361		{ 300000000, 150000000, 0, 0x0009, 0x04000005, 0x01030203, 0x04000005, 0x04000002,
1362		11, 0x0aaa0555 }
1363	};
1364	static n4m_table_t BCMINITDATA(type7_table)[] = {
1365		{ 183333333, 91666666, 0, 0x0605, 0x04000011, 0x11030011, 0x04000011, 0x04000003,
1366		11, 0x0aaa0555 },
1367		{ 187500000, 93750000, 0, 0x0a03, 0x04000011, 0x11030011, 0x04000011, 0x04000003,
1368		11, 0x0aaa0555 },
1369		{ 196875000, 98437500, 0, 0x1003, 0x11020005, 0x11050011, 0x11020005, 0x04000005,
1370		11, 0x0aaa0555 },
1371		{ 200000000, 100000000, 0, 0x0311, 0x04000011, 0x11030011, 0x04000009, 0x04000003,
1372		11, 0x0aaa0555 },
1373		{ 200000000, 100000000, 0, 0x0311, 0x04020011, 0x11030011, 0x04020011, 0x04020003,
1374		11, 0x0aaa0555 },
1375		{ 206250000, 103125000, 0, 0x1103, 0x11020005, 0x11050011, 0x11020005, 0x04000005,
1376		11, 0x0aaa0555 },
1377		{ 212500000, 106250000, 0, 0x0c05, 0x11020005, 0x01030303, 0x11020005, 0x04000005,
1378		11, 0x0aaa0555 },
1379		{ 215625000, 107812500, 0, 0x1203, 0x11090009, 0x11050005, 0x11020005, 0x04000005,
1380		11, 0x0aaa0555 },
1381		{ 216666666, 108333333, 0, 0x0805, 0x11020003, 0x11030011, 0x11020003, 0x04000003,
1382		11, 0x0aaa0555 },
1383		{ 225000000, 112500000, 0, 0x0d03, 0x11020003, 0x11030011, 0x11020003, 0x04000003,
1384		11, 0x0aaa0555 },
1385		{ 233333333, 116666666, 0, 0x0905, 0x11020003, 0x11030011, 0x11020003, 0x04000003,
1386		11, 0x0aaa0555 },
1387		{ 237500000, 118750000, 0, 0x0e05, 0x11020005, 0x11210005, 0x11020005, 0x04000005,
1388		11, 0x0aaa0555 },
1389		{ 240000000, 120000000, 0, 0x0b11, 0x11020009, 0x11210009, 0x11020009, 0x04000009,
1390		11, 0x0aaa0555 },
1391		{ 250000000, 125000000, 0, 0x0f03, 0x11020003, 0x11210003, 0x11020003, 0x04000003,
1392		11, 0x0aaa0555 }
1393	};
1394
1395	ulong start, end, dst;
1396	bool ret = FALSE;
1397
1398	volatile uint32 *dll_ctrl = (volatile uint32 *)0xff400008;
1399	volatile uint32 *dll_r1 = (volatile uint32 *)0xff400010;
1400	volatile uint32 *dll_r2 = (volatile uint32 *)0xff400018;
1401
1402	/* 5354 chipcommon pll setting can't be changed.
1403	 * The PMU on power up comes up with the default clk frequency
1404	 * of 240MHz
1405	 */
1406	if ((CHIPID(sih->chip) == BCM5354_CHIP_ID) || (CHIPID(sih->chip) == BCM53572_CHIP_ID))
1407		return TRUE;
1408
1409	if (sih->cccaps & CC_CAP_PMU)
1410		return mips_pmu_setclock(sih, mipsclock, siclock, pciclock);
1411
1412	osh = si_osh(sih);
1413
1414	/* get index of the current core */
1415	idx = si_coreidx(sih);
1416	clockcontrol_m2 = NULL;
1417
1418	/* switch to chipc core */
1419	cc = (chipcregs_t *)si_setcoreidx(sih, SI_CC_IDX);
1420	ASSERT(cc);
1421
1422	pll_type = sih->cccaps & CC_CAP_PLL_MASK;
1423	if (pll_type == PLL_TYPE6) {
1424		clockcontrol_n = NULL;
1425		clockcontrol_sb = NULL;
1426		clockcontrol_pci = NULL;
1427	} else {
1428		clockcontrol_n = &cc->clockcontrol_n;
1429		clockcontrol_sb = &cc->clockcontrol_sb;
1430		clockcontrol_pci = &cc->clockcontrol_pci;
1431		clockcontrol_m2 = &cc->clockcontrol_m2;
1432	}
1433
1434	if (pll_type == PLL_TYPE6) {
1435		/* Silence compilers */
1436		orig_n = orig_sb = orig_pci = 0;
1437	} else {
1438		/* Store the current clock register values */
1439		orig_n = R_REG(osh, clockcontrol_n);
1440		orig_sb = R_REG(osh, clockcontrol_sb);
1441		orig_pci = R_REG(osh, clockcontrol_pci);
1442	}
1443
1444	if (pll_type == PLL_TYPE3) {
1445		/* 5350 */
1446		if (CHIPID(sih->chip) != BCM5365_CHIP_ID) {
1447			/*
1448			 * Search for the closest MIPS clock less than or equal to
1449			 * a preferred value.
1450			 */
1451			for (i = 0; i < ARRAYSIZE(type3_table); i++) {
1452				if (type3_table[i].mipsclock > mipsclock)
1453					break;
1454			}
1455			if (i == 0) {
1456				ret = FALSE;
1457				goto done;
1458			} else {
1459				ret = TRUE;
1460				i--;
1461			}
1462			ASSERT(type3_table[i].mipsclock <= mipsclock);
1463
1464			/* No PLL change */
1465			orig_m2 = R_REG(osh, &cc->clockcontrol_m2);
1466			if ((orig_n == type3_table[i].n) &&
1467			    (orig_m2 == type3_table[i].m2)) {
1468				goto done;
1469			}
1470
1471			/* Set the PLL controls */
1472			W_REG(osh, clockcontrol_n, type3_table[i].n);
1473			W_REG(osh, clockcontrol_m2, type3_table[i].m2);
1474
1475			/* Reset */
1476			si_watchdog(sih, 1);
1477			while (1);
1478		}
1479	} else if ((pll_type == PLL_TYPE2) ||
1480	           (pll_type == PLL_TYPE4) ||
1481	           (pll_type == PLL_TYPE6) ||
1482	           (pll_type == PLL_TYPE7)) {
1483		n4m_table_t *table = NULL, *te;
1484		uint tabsz = 0;
1485
1486		ASSERT(cc);
1487
1488		orig_mips = R_REG(osh, &cc->clockcontrol_m3);
1489
1490		switch (pll_type) {
1491		case PLL_TYPE6: {
1492			uint32 new_mips = 0;
1493
1494			ret = TRUE;
1495			if (mipsclock <= SB2MIPS_T6(CC_T6_M1))
1496				new_mips = CC_T6_MMASK;
1497
1498			if (orig_mips == new_mips)
1499				goto done;
1500
1501			W_REG(osh, &cc->clockcontrol_m3, new_mips);
1502			goto end_fill;
1503		}
1504		case PLL_TYPE2:
1505			table = type2_table;
1506			tabsz = ARRAYSIZE(type2_table);
1507			break;
1508		case PLL_TYPE4:
1509			table = type4_table;
1510			tabsz = ARRAYSIZE(type4_table);
1511			break;
1512		case PLL_TYPE7:
1513			table = type7_table;
1514			tabsz = ARRAYSIZE(type7_table);
1515			break;
1516		default:
1517			ASSERT("No table for plltype" == NULL);
1518			break;
1519		}
1520
1521		/* Store the current clock register values */
1522		orig_m2 = R_REG(osh, &cc->clockcontrol_m2);
1523		orig_ratio_parm = 0;
1524		orig_ratio_cfg = 0;
1525
1526		/* Look up current ratio */
1527		for (i = 0; i < tabsz; i++) {
1528			if ((orig_n == table[i].n) &&
1529			    (orig_sb == table[i].sb) &&
1530			    (orig_pci == table[i].pci33) &&
1531			    (orig_m2 == table[i].m2) &&
1532			    (orig_mips == table[i].m3)) {
1533				orig_ratio_parm = table[i].ratio_parm;
1534				orig_ratio_cfg = table[i].ratio_cfg;
1535				break;
1536			}
1537		}
1538
1539		/* Search for the closest MIPS clock greater or equal to a preferred value */
1540		for (i = 0; i < tabsz; i++) {
1541			ASSERT(table[i].mipsclock ==
1542			       si_clock_rate(pll_type, table[i].n, table[i].m3));
1543			if ((mipsclock <= table[i].mipsclock) &&
1544			    ((siclock == 0) || (siclock <= table[i].sbclock)) &&
1545			    ((pciclock == 0) || (pciclock <= table[i].pciclock)))
1546				break;
1547		}
1548		if (i == tabsz) {
1549			ret = FALSE;
1550			goto done;
1551		} else {
1552			te = &table[i];
1553			ret = TRUE;
1554		}
1555
1556		/* No PLL change */
1557		if ((orig_n == te->n) &&
1558		    (orig_sb == te->sb) &&
1559		    (orig_pci == te->pci33) &&
1560		    (orig_m2 == te->m2) &&
1561		    (orig_mips == te->m3))
1562			goto done;
1563
1564		/* Set the PLL controls */
1565		W_REG(osh, clockcontrol_n, te->n);
1566		W_REG(osh, clockcontrol_sb, te->sb);
1567		W_REG(osh, clockcontrol_pci, te->pci33);
1568		W_REG(osh, &cc->clockcontrol_m2, te->m2);
1569		W_REG(osh, &cc->clockcontrol_m3, te->m3);
1570
1571		/* Set the chipcontrol bit to change mipsref to the backplane divider if needed */
1572		if ((pll_type == PLL_TYPE7) && (te->sb != te->m2) &&
1573		    (si_clock_rate(pll_type, te->n, te->m2) == 120000000))
1574			W_REG(osh, &cc->chipcontrol,
1575			      R_REG(osh, &cc->chipcontrol) | 0x100);
1576
1577		/* No ratio change */
1578		if (CHIPID(sih->chip) != BCM4785_CHIP_ID) {
1579			if (orig_ratio_parm == te->ratio_parm)
1580				goto end_fill;
1581		}
1582
1583		/* Preload the code into the cache */
1584		icache_probe(MFC0(C0_CONFIG, 1), &ic_size, &ic_lsize);
1585		if (CHIPID(sih->chip) == BCM4785_CHIP_ID) {
1586			start = ((ulong) &&start_fill_4785) & ~(ic_lsize - 1);
1587			end = ((ulong) &&end_fill_4785 + (ic_lsize - 1)) & ~(ic_lsize - 1);
1588		}
1589		else {
1590			start = ((ulong) &&start_fill) & ~(ic_lsize - 1);
1591			end = ((ulong) &&end_fill + (ic_lsize - 1)) & ~(ic_lsize - 1);
1592		}
1593		while (start < end) {
1594			cache_op(start, Fill_I);
1595			start += ic_lsize;
1596		}
1597
1598		/* 4785 clock freq change procedures */
1599		if (CHIPID(sih->chip) == BCM4785_CHIP_ID) {
1600	start_fill_4785:
1601			/* Switch to async */
1602			MTC0(C0_BROADCOM, 4, (1 << 22));
1603
1604			/* Set clock ratio in MIPS */
1605			*dll_r1 = (*dll_r1 & 0xfffffff0) | (te->dll_r1 - 1);
1606			*dll_r2 = te->dll_r2;
1607
1608			/* Enable new settings in MIPS */
1609			*dll_r1 = *dll_r1 | 0xc0000000;
1610
1611			/* Set active cfg */
1612			MTC0(C0_BROADCOM, 2, MFC0(C0_BROADCOM, 2) | (1 << 3) | 1);
1613
1614			/* Fake soft reset (clock cfg registers not reset) */
1615			MTC0(C0_BROADCOM, 5, MFC0(C0_BROADCOM, 5) | (1 << 2));
1616
1617			/* Clear active cfg */
1618			MTC0(C0_BROADCOM, 2, MFC0(C0_BROADCOM, 2) & ~(1 << 3));
1619
1620			/* set watchdog timer */
1621			W_REG(osh, &cc->watchdog, 20);
1622			(void) R_REG(osh, &cc->chipid);
1623
1624			/* wait for timer interrupt */
1625			__asm__ __volatile__(
1626				".set\tmips3\n\t"
1627				"sync\n\t"
1628				"wait\n\t"
1629				".set\tmips0");
1630	end_fill_4785:
1631			while (1);
1632		}
1633		/* Generic clock freq change procedures */
1634		else {
1635			/* Copy the handler */
1636			start = (ulong) &handler;
1637			end = (ulong) &afterhandler;
1638			dst = KSEG1ADDR(0x180);
1639			for (i = 0; i < (end - start); i += 4)
1640				*((ulong *)(dst + i)) = *((ulong *)(start + i));
1641
1642			/* Preload the handler into the cache one line at a time */
1643			for (i = 0; i < (end - start); i += ic_lsize)
1644				cache_op(dst + i, Fill_I);
1645
1646			/* Clear BEV bit */
1647			MTC0(C0_STATUS, 0, MFC0(C0_STATUS, 0) & ~ST0_BEV);
1648
1649			/* Enable interrupts */
1650			MTC0(C0_STATUS, 0, MFC0(C0_STATUS, 0) | (ALLINTS | ST0_IE));
1651
1652			/* Enable MIPS timer interrupt */
1653			mipsr = si_setcore(sih, MIPS33_CORE_ID, 0);
1654			ASSERT(mipsr);
1655			W_REG(osh, &mipsr->intmask, 1);
1656
1657	start_fill:
1658			/* step 1, set clock ratios */
1659			MTC0(C0_BROADCOM, 3, te->ratio_parm);
1660			MTC0(C0_BROADCOM, 1, te->ratio_cfg);
1661
1662			/* step 2: program timer intr */
1663			W_REG(osh, &mipsr->timer, 100);
1664			(void) R_REG(osh, &mipsr->timer);
1665
1666			/* step 3, switch to async */
1667			sync_mode = MFC0(C0_BROADCOM, 4);
1668			MTC0(C0_BROADCOM, 4, 1 << 22);
1669
1670			/* step 4, set cfg active */
1671			MTC0(C0_BROADCOM, 2, (1 << 3) | 1);
1672
1673			/* steps 5 & 6 */
1674			__asm__ __volatile__(
1675				".set\tmips3\n\t"
1676				"wait\n\t"
1677				".set\tmips0");
1678
1679			/* step 7, clear cfg active */
1680			MTC0(C0_BROADCOM, 2, 0);
1681
1682			/* Additional Step: set back to orig sync mode */
1683			MTC0(C0_BROADCOM, 4, sync_mode);
1684
1685			/* step 8, fake soft reset */
1686			MTC0(C0_BROADCOM, 5, MFC0(C0_BROADCOM, 5) | (1 << 2));
1687
1688	end_fill:
1689			/* set watchdog timer */
1690			W_REG(osh, &cc->watchdog, 20);
1691			(void) R_REG(osh, &cc->chipid);
1692
1693			/* wait for timer interrupt */
1694			__asm__ __volatile__(
1695				".set\tmips3\n\t"
1696				"sync\n\t"
1697				"wait\n\t"
1698				".set\tmips0");
1699			while (1);
1700		}
1701	}
1702
1703done:
1704	/* Enable 4785 DLL */
1705	if (CHIPID(sih->chip) == BCM4785_CHIP_ID) {
1706		uint32 tmp;
1707
1708		/* set mask to 1e, enable DLL (bit 0) */
1709		*dll_ctrl |= 0x0041e021;
1710
1711		/* enable aggressive hardware mode */
1712		*dll_ctrl |= 0x00000080;
1713
1714		/* wait for lock flag to clear */
1715		while ((*dll_ctrl & 0x2) == 0);
1716
1717		/* clear sticky flags (clear on write 1) */
1718		tmp = *dll_ctrl;
1719		*dll_ctrl = tmp;
1720
1721		/* set mask to 5b'10001 */
1722		*dll_ctrl = (*dll_ctrl & 0xfffc1fff) | 0x00022000;
1723
1724		/* enable sync mode */
1725		MTC0(C0_BROADCOM, 4, MFC0(C0_BROADCOM, 4) & 0xfe3fffff);
1726		(void)MFC0(C0_BROADCOM, 4);
1727	}
1728
1729	/* switch back to previous core */
1730	si_setcoreidx(sih, idx);
1731
1732	return ret;
1733}
1734
1735void
1736BCMINITFN(enable_pfc)(uint32 mode)
1737{
1738	uint32 prid;
1739	ulong start, end;
1740	uint ic_size, ic_lsize;
1741
1742	prid = MFC0(C0_PRID, 0);
1743	if (!BCM330X(prid))
1744		return;
1745
1746	/* enable prefetch cache if available */
1747	if (MFC0(C0_BROADCOM, 0) & BRCM_PFC_AVAIL) {
1748		/* If auto then choose the correct mode for this
1749		 * platform, currently we only ever select one mode
1750		 */
1751		if (mode == PFC_AUTO)
1752			mode = PFC_INST;
1753
1754		icache_probe(MFC0(C0_CONFIG, 1), &ic_size, &ic_lsize);
1755
1756		start = ((ulong) &&setpfc_start) & ~(ic_lsize - 1);
1757		end = ((ulong) &&setpfc_end + (ic_lsize - 1)) & ~(ic_lsize - 1);
1758
1759		/* Preload setpfc code into the cache one line at a time */
1760		while (start < end) {
1761			cache_op(start, Fill_I);
1762			start += ic_lsize;
1763		}
1764
1765		/* Now set the pfc */
1766	setpfc_start:
1767		/* write range */
1768		*(volatile uint32 *)PFC_CR1 = 0xffff0000;
1769
1770		/* enable */
1771		*(volatile uint32 *)PFC_CR0 = mode;
1772	setpfc_end:
1773		/* Compiler foder */
1774		ic_size = 0;
1775	}
1776}
1777
1778/* returns the ncdl value to be programmed into sdram_ncdl for calibration */
1779uint32
1780BCMINITFN(si_memc_get_ncdl)(si_t *sih)
1781{
1782	osl_t *osh;
1783	sbmemcregs_t *memc;
1784	uint32 ret = 0;
1785	uint32 config, rd, wr, misc, dqsg, cd, sm, sd;
1786	uint idx, rev;
1787
1788	osh = si_osh(sih);
1789
1790	idx = si_coreidx(sih);
1791
1792	memc = (sbmemcregs_t *)si_setcore(sih, MEMC_CORE_ID, 0);
1793	if (memc == NULL)
1794		goto out;
1795
1796	rev = si_corerev(sih);
1797
1798	config = R_REG(osh, &memc->config);
1799	wr = R_REG(osh, &memc->wrncdlcor);
1800	rd = R_REG(osh, &memc->rdncdlcor);
1801	misc = R_REG(osh, &memc->miscdlyctl);
1802	dqsg = R_REG(osh, &memc->dqsgatencdl);
1803
1804	rd &= MEMC_RDNCDLCOR_RD_MASK;
1805	wr &= MEMC_WRNCDLCOR_WR_MASK;
1806	dqsg &= MEMC_DQSGATENCDL_G_MASK;
1807
1808	if (config & MEMC_CONFIG_DDR) {
1809		ret = (wr << 16) | (rd << 8) | dqsg;
1810	} else {
1811		if (rev > 0)
1812			cd = rd;
1813		else
1814			cd = (rd == MEMC_CD_THRESHOLD) ? rd : (wr + MEMC_CD_THRESHOLD);
1815		sm = (misc & MEMC_MISC_SM_MASK) >> MEMC_MISC_SM_SHIFT;
1816		sd = (misc & MEMC_MISC_SD_MASK) >> MEMC_MISC_SD_SHIFT;
1817		ret = (sm << 16) | (sd << 8) | cd;
1818	}
1819
1820out:
1821	/* switch back to previous core */
1822	si_setcoreidx(sih, idx);
1823
1824	return ret;
1825}
1826
1827void
1828hnd_cpu_reset(si_t *sih)
1829{
1830	if (CHIPID(sih->chip) == BCM4785_CHIP_ID)
1831		MTC0(C0_BROADCOM, 4, (1 << 22));
1832	si_watchdog(sih, 1);
1833	if (CHIPID(sih->chip) == BCM4785_CHIP_ID) {
1834		__asm__ __volatile__(
1835			".set\tmips3\n\t"
1836			"sync\n\t"
1837			"wait\n\t"
1838			".set\tmips0");
1839	}
1840	while (1);
1841}
1842
1843#if defined(BCMPERFSTATS)
1844/*
1845 * CP0 Register 25 supports 4 semi-independent 32bit performance counters.
1846 * $25 select 0, 1, 2, and 3 are the counters.  The counters *decrement* (who thought this one up?)
1847 * $25 select 4 and 5 each contain 2-16bit control fields, one for each of the 4 counters
1848 * $25 select 6 is the global perf control register.
1849 */
1850/* enable and start instruction counting */
1851
1852void
1853hndmips_perf_cyclecount_enable(void)
1854{
1855	MTC0(C0_PERFORMANCE, 6, 0x80000200);	/* global enable perf counters */
1856	MTC0(C0_PERFORMANCE, 4,
1857	     0x8048 | MFC0(C0_PERFORMANCE, 4));	/* enable cycles counting for counter 0 */
1858	MTC0(C0_PERFORMANCE, 0, 0);		/* zero counter zero */
1859}
1860
1861void
1862hndmips_perf_instrcount_enable(void)
1863{
1864	MTC0(C0_PERFORMANCE, 6, 0x80000200);	/* global enable perf counters */
1865	MTC0(C0_PERFORMANCE, 4,
1866	     0x8044 | MFC0(C0_PERFORMANCE, 4));	/* enable instructions counting for counter 0 */
1867	MTC0(C0_PERFORMANCE, 0, 0);		/* zero counter zero */
1868}
1869
1870/* enable and start I$ hit and I$ miss counting */
1871void
1872hndmips_perf_icachecount_enable(void)
1873{
1874	MTC0(C0_PERFORMANCE, 6, 0x80000218);	/* enable I$ counting */
1875	MTC0(C0_PERFORMANCE, 4, 0x80148018);	/* count I$ hits in cntr 0 and misses in cntr 1 */
1876	MTC0(C0_PERFORMANCE, 0, 0);		/* zero counter 0 - # I$ hits */
1877	MTC0(C0_PERFORMANCE, 1, 0);		/* zero counter 1 - # I$ misses */
1878}
1879
1880/* enable and start D$ hit and I$ miss counting */
1881void
1882hndmips_perf_dcachecount_enable(void)
1883{
1884	MTC0(C0_PERFORMANCE, 6, 0x80000211);	/* enable D$ counting */
1885	MTC0(C0_PERFORMANCE, 4, 0x80248028);	/* count D$ hits in cntr 0 and misses in cntr 1 */
1886	MTC0(C0_PERFORMANCE, 0, 0);		/* zero counter 0 - # D$ hits */
1887	MTC0(C0_PERFORMANCE, 1, 0);		/* zero counter 1 - # D$ misses */
1888}
1889
1890void
1891hndmips_perf_icache_miss_enable()
1892{
1893	MTC0(C0_PERFORMANCE, 4,
1894	     0x80140000 | MFC0(C0_PERFORMANCE, 4)); /* enable cache misses counting for counter 1 */
1895	MTC0(C0_PERFORMANCE, 1, 0); /* zero counter one */
1896}
1897
1898
1899void
1900hndmips_perf_icache_hit_enable()
1901{
1902	MTC0(C0_PERFORMANCE, 5, 0x8018 | MFC0(C0_PERFORMANCE, 5));
1903	/* enable cache hits counting for counter 2 */
1904	MTC0(C0_PERFORMANCE, 2, 0);		/* zero counter 2 */
1905}
1906
1907uint32
1908hndmips_perf_read_instrcount()
1909{
1910	return -(long)(MFC0(C0_PERFORMANCE, 0));
1911}
1912
1913uint32
1914hndmips_perf_read_cache_miss()
1915{
1916	return -(long)(MFC0(C0_PERFORMANCE, 1));
1917}
1918
1919uint32
1920hndmips_perf_read_cache_hit()
1921{
1922	return -(long)(MFC0(C0_PERFORMANCE, 2));
1923}
1924
1925#endif
1926