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