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