aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/boot/4xx.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/boot/4xx.c')
-rw-r--r--arch/powerpc/boot/4xx.c272
1 files changed, 204 insertions, 68 deletions
diff --git a/arch/powerpc/boot/4xx.c b/arch/powerpc/boot/4xx.c
index d16ea10d7546..1a83efe274c1 100644
--- a/arch/powerpc/boot/4xx.c
+++ b/arch/powerpc/boot/4xx.c
@@ -275,89 +275,225 @@ void ibm4xx_fixup_ebc_ranges(const char *ebc)
275 setprop(devp, "ranges", ranges, (p - ranges) * sizeof(u32)); 275 setprop(devp, "ranges", ranges, (p - ranges) * sizeof(u32));
276} 276}
277 277
278#define SPRN_CCR1 0x378 278/* Calculate 440GP clocks */
279void ibm440ep_fixup_clocks(unsigned int sysclk, unsigned int ser_clk) 279void ibm440gp_fixup_clocks(unsigned int sys_clk, unsigned int ser_clk)
280{ 280{
281 u32 cpu, plb, opb, ebc, tb, uart0, m, vco; 281 u32 sys0 = mfdcr(DCRN_CPC0_SYS0);
282 u32 reg; 282 u32 cr0 = mfdcr(DCRN_CPC0_CR0);
283 u32 fwdva, fwdvb, fbdv, lfbdv, opbdv0, perdv0, spcid0, prbdv0, tmp; 283 u32 cpu, plb, opb, ebc, tb, uart0, uart1, m;
284 284 u32 opdv = CPC0_SYS0_OPDV(sys0);
285 mtdcr(DCRN_CPR0_ADDR, CPR0_PLLD0); 285 u32 epdv = CPC0_SYS0_EPDV(sys0);
286 reg = mfdcr(DCRN_CPR0_DATA); 286
287 tmp = (reg & 0x000F0000) >> 16; 287 if (sys0 & CPC0_SYS0_BYPASS) {
288 fwdva = tmp ? tmp : 16; 288 /* Bypass system PLL */
289 tmp = (reg & 0x00000700) >> 8; 289 cpu = plb = sys_clk;
290 fwdvb = tmp ? tmp : 8; 290 } else {
291 tmp = (reg & 0x1F000000) >> 24; 291 if (sys0 & CPC0_SYS0_EXTSL)
292 fbdv = tmp ? tmp : 32; 292 /* PerClk */
293 lfbdv = (reg & 0x0000007F); 293 m = CPC0_SYS0_FWDVB(sys0) * opdv * epdv;
294
295 mtdcr(DCRN_CPR0_ADDR, CPR0_OPBD0);
296 reg = mfdcr(DCRN_CPR0_DATA);
297 tmp = (reg & 0x03000000) >> 24;
298 opbdv0 = tmp ? tmp : 4;
299
300 mtdcr(DCRN_CPR0_ADDR, CPR0_PERD0);
301 reg = mfdcr(DCRN_CPR0_DATA);
302 tmp = (reg & 0x07000000) >> 24;
303 perdv0 = tmp ? tmp : 8;
304
305 mtdcr(DCRN_CPR0_ADDR, CPR0_PRIMBD0);
306 reg = mfdcr(DCRN_CPR0_DATA);
307 tmp = (reg & 0x07000000) >> 24;
308 prbdv0 = tmp ? tmp : 8;
309
310 mtdcr(DCRN_CPR0_ADDR, CPR0_SCPID);
311 reg = mfdcr(DCRN_CPR0_DATA);
312 tmp = (reg & 0x03000000) >> 24;
313 spcid0 = tmp ? tmp : 4;
314
315 /* Calculate M */
316 mtdcr(DCRN_CPR0_ADDR, CPR0_PLLC0);
317 reg = mfdcr(DCRN_CPR0_DATA);
318 tmp = (reg & 0x03000000) >> 24;
319 if (tmp == 0) { /* PLL output */
320 tmp = (reg & 0x20000000) >> 29;
321 if (!tmp) /* PLLOUTA */
322 m = fbdv * lfbdv * fwdva;
323 else 294 else
324 m = fbdv * lfbdv * fwdvb; 295 /* CPU clock */
296 m = CPC0_SYS0_FBDV(sys0) * CPC0_SYS0_FWDVA(sys0);
297 cpu = sys_clk * m / CPC0_SYS0_FWDVA(sys0);
298 plb = sys_clk * m / CPC0_SYS0_FWDVB(sys0);
325 } 299 }
326 else if (tmp == 1) /* CPU output */ 300
327 m = fbdv * fwdva; 301 opb = plb / opdv;
302 ebc = opb / epdv;
303
304 /* FIXME: Check if this is for all 440GP, or just Ebony */
305 if ((mfpvr() & 0xf0000fff) == 0x40000440)
306 /* Rev. B 440GP, use external system clock */
307 tb = sys_clk;
328 else 308 else
329 m = perdv0 * opbdv0 * fwdvb; 309 /* Rev. C 440GP, errata force us to use internal clock */
310 tb = cpu;
330 311
331 vco = (m * sysclk) + (m >> 1); 312 if (cr0 & CPC0_CR0_U0EC)
332 cpu = vco / fwdva; 313 /* External UART clock */
333 plb = vco / fwdvb / prbdv0; 314 uart0 = ser_clk;
334 opb = plb / opbdv0; 315 else
335 ebc = plb / perdv0; 316 /* Internal UART clock */
317 uart0 = plb / CPC0_CR0_UDIV(cr0);
318
319 if (cr0 & CPC0_CR0_U1EC)
320 /* External UART clock */
321 uart1 = ser_clk;
322 else
323 /* Internal UART clock */
324 uart1 = plb / CPC0_CR0_UDIV(cr0);
325
326 printf("PPC440GP: SysClk = %dMHz (%x)\n\r",
327 (sys_clk + 500000) / 1000000, sys_clk);
328
329 dt_fixup_cpu_clocks(cpu, tb, 0);
330
331 dt_fixup_clock("/plb", plb);
332 dt_fixup_clock("/plb/opb", opb);
333 dt_fixup_clock("/plb/opb/ebc", ebc);
334 dt_fixup_clock("/plb/opb/serial@40000200", uart0);
335 dt_fixup_clock("/plb/opb/serial@40000300", uart1);
336}
337
338#define SPRN_CCR1 0x378
339
340static inline u32 __fix_zero(u32 v, u32 def)
341{
342 return v ? v : def;
343}
344
345static unsigned int __ibm440eplike_fixup_clocks(unsigned int sys_clk,
346 unsigned int tmr_clk,
347 int per_clk_from_opb)
348{
349 /* PLL config */
350 u32 pllc = CPR0_READ(DCRN_CPR0_PLLC);
351 u32 plld = CPR0_READ(DCRN_CPR0_PLLD);
352
353 /* Dividers */
354 u32 fbdv = __fix_zero((plld >> 24) & 0x1f, 32);
355 u32 fwdva = __fix_zero((plld >> 16) & 0xf, 16);
356 u32 fwdvb = __fix_zero((plld >> 8) & 7, 8);
357 u32 lfbdv = __fix_zero(plld & 0x3f, 64);
358 u32 pradv0 = __fix_zero((CPR0_READ(DCRN_CPR0_PRIMAD) >> 24) & 7, 8);
359 u32 prbdv0 = __fix_zero((CPR0_READ(DCRN_CPR0_PRIMBD) >> 24) & 7, 8);
360 u32 opbdv0 = __fix_zero((CPR0_READ(DCRN_CPR0_OPBD) >> 24) & 3, 4);
361 u32 perdv0 = __fix_zero((CPR0_READ(DCRN_CPR0_PERD) >> 24) & 3, 4);
362
363 /* Input clocks for primary dividers */
364 u32 clk_a, clk_b;
365
366 /* Resulting clocks */
367 u32 cpu, plb, opb, ebc, vco;
368
369 /* Timebase */
370 u32 ccr1, tb = tmr_clk;
371
372 if (pllc & 0x40000000) {
373 u32 m;
374
375 /* Feedback path */
376 switch ((pllc >> 24) & 7) {
377 case 0:
378 /* PLLOUTx */
379 m = ((pllc & 0x20000000) ? fwdvb : fwdva) * lfbdv;
380 break;
381 case 1:
382 /* CPU */
383 m = fwdva * pradv0;
384 break;
385 case 5:
386 /* PERClk */
387 m = fwdvb * prbdv0 * opbdv0 * perdv0;
388 break;
389 default:
390 printf("WARNING ! Invalid PLL feedback source !\n");
391 goto bypass;
392 }
393 m *= fbdv;
394 vco = sys_clk * m;
395 clk_a = vco / fwdva;
396 clk_b = vco / fwdvb;
397 } else {
398bypass:
399 /* Bypass system PLL */
400 vco = 0;
401 clk_a = clk_b = sys_clk;
402 }
336 403
337 /* FIXME */ 404 cpu = clk_a / pradv0;
338 uart0 = ser_clk; 405 plb = clk_b / prbdv0;
406 opb = plb / opbdv0;
407 ebc = (per_clk_from_opb ? opb : plb) / perdv0;
339 408
340 /* Figure out timebase. Either CPU or default TmrClk */ 409 /* Figure out timebase. Either CPU or default TmrClk */
341 asm volatile ( 410 ccr1 = mfspr(SPRN_CCR1);
342 "mfspr %0,%1\n" 411
343 : 412 /* If passed a 0 tmr_clk, force CPU clock */
344 "=&r"(reg) : "i"(SPRN_CCR1)); 413 if (tb == 0) {
345 if (reg & 0x0080) 414 ccr1 &= ~0x80u;
346 tb = 25000000; /* TmrClk is 25MHz */ 415 mtspr(SPRN_CCR1, ccr1);
347 else 416 }
417 if ((ccr1 & 0x0080) == 0)
348 tb = cpu; 418 tb = cpu;
349 419
350 dt_fixup_cpu_clocks(cpu, tb, 0); 420 dt_fixup_cpu_clocks(cpu, tb, 0);
351 dt_fixup_clock("/plb", plb); 421 dt_fixup_clock("/plb", plb);
352 dt_fixup_clock("/plb/opb", opb); 422 dt_fixup_clock("/plb/opb", opb);
353 dt_fixup_clock("/plb/opb/ebc", ebc); 423 dt_fixup_clock("/plb/opb/ebc", ebc);
354 dt_fixup_clock("/plb/opb/serial@ef600300", uart0); 424
355 dt_fixup_clock("/plb/opb/serial@ef600400", uart0); 425 return plb;
356 dt_fixup_clock("/plb/opb/serial@ef600500", uart0); 426}
357 dt_fixup_clock("/plb/opb/serial@ef600600", uart0); 427
428static void eplike_fixup_uart_clk(int index, const char *path,
429 unsigned int ser_clk,
430 unsigned int plb_clk)
431{
432 unsigned int sdr;
433 unsigned int clock;
434
435 switch (index) {
436 case 0:
437 sdr = SDR0_READ(DCRN_SDR0_UART0);
438 break;
439 case 1:
440 sdr = SDR0_READ(DCRN_SDR0_UART1);
441 break;
442 case 2:
443 sdr = SDR0_READ(DCRN_SDR0_UART2);
444 break;
445 case 3:
446 sdr = SDR0_READ(DCRN_SDR0_UART3);
447 break;
448 default:
449 return;
450 }
451
452 if (sdr & 0x00800000u)
453 clock = ser_clk;
454 else
455 clock = plb_clk / __fix_zero(sdr & 0xff, 256);
456
457 dt_fixup_clock(path, clock);
458}
459
460void ibm440ep_fixup_clocks(unsigned int sys_clk,
461 unsigned int ser_clk,
462 unsigned int tmr_clk)
463{
464 unsigned int plb_clk = __ibm440eplike_fixup_clocks(sys_clk, tmr_clk, 0);
465
466 /* serial clocks beed fixup based on int/ext */
467 eplike_fixup_uart_clk(0, "/plb/opb/serial@ef600300", ser_clk, plb_clk);
468 eplike_fixup_uart_clk(1, "/plb/opb/serial@ef600400", ser_clk, plb_clk);
469 eplike_fixup_uart_clk(2, "/plb/opb/serial@ef600500", ser_clk, plb_clk);
470 eplike_fixup_uart_clk(3, "/plb/opb/serial@ef600600", ser_clk, plb_clk);
471}
472
473void ibm440gx_fixup_clocks(unsigned int sys_clk,
474 unsigned int ser_clk,
475 unsigned int tmr_clk)
476{
477 unsigned int plb_clk = __ibm440eplike_fixup_clocks(sys_clk, tmr_clk, 1);
478
479 /* serial clocks beed fixup based on int/ext */
480 eplike_fixup_uart_clk(0, "/plb/opb/serial@40000200", ser_clk, plb_clk);
481 eplike_fixup_uart_clk(1, "/plb/opb/serial@40000300", ser_clk, plb_clk);
482}
483
484void ibm440spe_fixup_clocks(unsigned int sys_clk,
485 unsigned int ser_clk,
486 unsigned int tmr_clk)
487{
488 unsigned int plb_clk = __ibm440eplike_fixup_clocks(sys_clk, tmr_clk, 1);
489
490 /* serial clocks beed fixup based on int/ext */
491 eplike_fixup_uart_clk(0, "/plb/opb/serial@10000200", ser_clk, plb_clk);
492 eplike_fixup_uart_clk(1, "/plb/opb/serial@10000300", ser_clk, plb_clk);
493 eplike_fixup_uart_clk(2, "/plb/opb/serial@10000600", ser_clk, plb_clk);
358} 494}
359 495
360void ibm405gp_fixup_clocks(unsigned int sysclk, unsigned int ser_clk) 496void ibm405gp_fixup_clocks(unsigned int sys_clk, unsigned int ser_clk)
361{ 497{
362 u32 pllmr = mfdcr(DCRN_CPC0_PLLMR); 498 u32 pllmr = mfdcr(DCRN_CPC0_PLLMR);
363 u32 cpc0_cr0 = mfdcr(DCRN_405_CPC0_CR0); 499 u32 cpc0_cr0 = mfdcr(DCRN_405_CPC0_CR0);
@@ -374,7 +510,7 @@ void ibm405gp_fixup_clocks(unsigned int sysclk, unsigned int ser_clk)
374 510
375 m = fwdv * fbdv * cbdv; 511 m = fwdv * fbdv * cbdv;
376 512
377 cpu = sysclk * m / fwdv; 513 cpu = sys_clk * m / fwdv;
378 plb = cpu / cbdv; 514 plb = cpu / cbdv;
379 opb = plb / opdv; 515 opb = plb / opdv;
380 ebc = plb / epdv; 516 ebc = plb / epdv;