Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/powerpc/boot/4xx.c
10817 views
1
/*
2
* Copyright 2007 David Gibson, IBM Corporation.
3
*
4
* Based on earlier code:
5
* Matt Porter <[email protected]>
6
* Copyright 2002-2005 MontaVista Software Inc.
7
*
8
* Eugene Surovegin <[email protected]> or <[email protected]>
9
* Copyright (c) 2003, 2004 Zultys Technologies
10
*
11
* Copyright (C) 2009 Wind River Systems, Inc.
12
* Updated for supporting PPC405EX on Kilauea.
13
* Tiejun Chen <[email protected]>
14
*
15
* This program is free software; you can redistribute it and/or
16
* modify it under the terms of the GNU General Public License
17
* as published by the Free Software Foundation; either version
18
* 2 of the License, or (at your option) any later version.
19
*/
20
#include <stddef.h>
21
#include "types.h"
22
#include "string.h"
23
#include "stdio.h"
24
#include "ops.h"
25
#include "reg.h"
26
#include "dcr.h"
27
28
static unsigned long chip_11_errata(unsigned long memsize)
29
{
30
unsigned long pvr;
31
32
pvr = mfpvr();
33
34
switch (pvr & 0xf0000ff0) {
35
case 0x40000850:
36
case 0x400008d0:
37
case 0x200008d0:
38
memsize -= 4096;
39
break;
40
default:
41
break;
42
}
43
44
return memsize;
45
}
46
47
/* Read the 4xx SDRAM controller to get size of system memory. */
48
void ibm4xx_sdram_fixup_memsize(void)
49
{
50
int i;
51
unsigned long memsize, bank_config;
52
53
memsize = 0;
54
for (i = 0; i < ARRAY_SIZE(sdram_bxcr); i++) {
55
bank_config = SDRAM0_READ(sdram_bxcr[i]);
56
if (bank_config & SDRAM_CONFIG_BANK_ENABLE)
57
memsize += SDRAM_CONFIG_BANK_SIZE(bank_config);
58
}
59
60
memsize = chip_11_errata(memsize);
61
dt_fixup_memory(0, memsize);
62
}
63
64
/* Read the 440SPe MQ controller to get size of system memory. */
65
#define DCRN_MQ0_B0BAS 0x40
66
#define DCRN_MQ0_B1BAS 0x41
67
#define DCRN_MQ0_B2BAS 0x42
68
#define DCRN_MQ0_B3BAS 0x43
69
70
static u64 ibm440spe_decode_bas(u32 bas)
71
{
72
u64 base = ((u64)(bas & 0xFFE00000u)) << 2;
73
74
/* open coded because I'm paranoid about invalid values */
75
switch ((bas >> 4) & 0xFFF) {
76
case 0:
77
return 0;
78
case 0xffc:
79
return base + 0x000800000ull;
80
case 0xff8:
81
return base + 0x001000000ull;
82
case 0xff0:
83
return base + 0x002000000ull;
84
case 0xfe0:
85
return base + 0x004000000ull;
86
case 0xfc0:
87
return base + 0x008000000ull;
88
case 0xf80:
89
return base + 0x010000000ull;
90
case 0xf00:
91
return base + 0x020000000ull;
92
case 0xe00:
93
return base + 0x040000000ull;
94
case 0xc00:
95
return base + 0x080000000ull;
96
case 0x800:
97
return base + 0x100000000ull;
98
}
99
printf("Memory BAS value 0x%08x unsupported !\n", bas);
100
return 0;
101
}
102
103
void ibm440spe_fixup_memsize(void)
104
{
105
u64 banktop, memsize = 0;
106
107
/* Ultimately, we should directly construct the memory node
108
* so we are able to handle holes in the memory address space
109
*/
110
banktop = ibm440spe_decode_bas(mfdcr(DCRN_MQ0_B0BAS));
111
if (banktop > memsize)
112
memsize = banktop;
113
banktop = ibm440spe_decode_bas(mfdcr(DCRN_MQ0_B1BAS));
114
if (banktop > memsize)
115
memsize = banktop;
116
banktop = ibm440spe_decode_bas(mfdcr(DCRN_MQ0_B2BAS));
117
if (banktop > memsize)
118
memsize = banktop;
119
banktop = ibm440spe_decode_bas(mfdcr(DCRN_MQ0_B3BAS));
120
if (banktop > memsize)
121
memsize = banktop;
122
123
dt_fixup_memory(0, memsize);
124
}
125
126
127
/* 4xx DDR1/2 Denali memory controller support */
128
/* DDR0 registers */
129
#define DDR0_02 2
130
#define DDR0_08 8
131
#define DDR0_10 10
132
#define DDR0_14 14
133
#define DDR0_42 42
134
#define DDR0_43 43
135
136
/* DDR0_02 */
137
#define DDR_START 0x1
138
#define DDR_START_SHIFT 0
139
#define DDR_MAX_CS_REG 0x3
140
#define DDR_MAX_CS_REG_SHIFT 24
141
#define DDR_MAX_COL_REG 0xf
142
#define DDR_MAX_COL_REG_SHIFT 16
143
#define DDR_MAX_ROW_REG 0xf
144
#define DDR_MAX_ROW_REG_SHIFT 8
145
/* DDR0_08 */
146
#define DDR_DDR2_MODE 0x1
147
#define DDR_DDR2_MODE_SHIFT 0
148
/* DDR0_10 */
149
#define DDR_CS_MAP 0x3
150
#define DDR_CS_MAP_SHIFT 8
151
/* DDR0_14 */
152
#define DDR_REDUC 0x1
153
#define DDR_REDUC_SHIFT 16
154
/* DDR0_42 */
155
#define DDR_APIN 0x7
156
#define DDR_APIN_SHIFT 24
157
/* DDR0_43 */
158
#define DDR_COL_SZ 0x7
159
#define DDR_COL_SZ_SHIFT 8
160
#define DDR_BANK8 0x1
161
#define DDR_BANK8_SHIFT 0
162
163
#define DDR_GET_VAL(val, mask, shift) (((val) >> (shift)) & (mask))
164
165
/*
166
* Some U-Boot versions set the number of chipselects to two
167
* for Sequoia/Rainier boards while they only have one chipselect
168
* hardwired. Hardcode the number of chipselects to one
169
* for sequioa/rainer board models or read the actual value
170
* from the memory controller register DDR0_10 otherwise.
171
*/
172
static inline u32 ibm4xx_denali_get_cs(void)
173
{
174
void *devp;
175
char model[64];
176
u32 val, cs;
177
178
devp = finddevice("/");
179
if (!devp)
180
goto read_cs;
181
182
if (getprop(devp, "model", model, sizeof(model)) <= 0)
183
goto read_cs;
184
185
model[sizeof(model)-1] = 0;
186
187
if (!strcmp(model, "amcc,sequoia") ||
188
!strcmp(model, "amcc,rainier"))
189
return 1;
190
191
read_cs:
192
/* get CS value */
193
val = SDRAM0_READ(DDR0_10);
194
195
val = DDR_GET_VAL(val, DDR_CS_MAP, DDR_CS_MAP_SHIFT);
196
cs = 0;
197
while (val) {
198
if (val & 0x1)
199
cs++;
200
val = val >> 1;
201
}
202
return cs;
203
}
204
205
void ibm4xx_denali_fixup_memsize(void)
206
{
207
u32 val, max_cs, max_col, max_row;
208
u32 cs, col, row, bank, dpath;
209
unsigned long memsize;
210
211
val = SDRAM0_READ(DDR0_02);
212
if (!DDR_GET_VAL(val, DDR_START, DDR_START_SHIFT))
213
fatal("DDR controller is not initialized\n");
214
215
/* get maximum cs col and row values */
216
max_cs = DDR_GET_VAL(val, DDR_MAX_CS_REG, DDR_MAX_CS_REG_SHIFT);
217
max_col = DDR_GET_VAL(val, DDR_MAX_COL_REG, DDR_MAX_COL_REG_SHIFT);
218
max_row = DDR_GET_VAL(val, DDR_MAX_ROW_REG, DDR_MAX_ROW_REG_SHIFT);
219
220
cs = ibm4xx_denali_get_cs();
221
if (!cs)
222
fatal("No memory installed\n");
223
if (cs > max_cs)
224
fatal("DDR wrong CS configuration\n");
225
226
/* get data path bytes */
227
val = SDRAM0_READ(DDR0_14);
228
229
if (DDR_GET_VAL(val, DDR_REDUC, DDR_REDUC_SHIFT))
230
dpath = 4; /* 32 bits */
231
else
232
dpath = 8; /* 64 bits */
233
234
/* get address pins (rows) */
235
val = SDRAM0_READ(DDR0_42);
236
237
row = DDR_GET_VAL(val, DDR_APIN, DDR_APIN_SHIFT);
238
if (row > max_row)
239
fatal("DDR wrong APIN configuration\n");
240
row = max_row - row;
241
242
/* get collomn size and banks */
243
val = SDRAM0_READ(DDR0_43);
244
245
col = DDR_GET_VAL(val, DDR_COL_SZ, DDR_COL_SZ_SHIFT);
246
if (col > max_col)
247
fatal("DDR wrong COL configuration\n");
248
col = max_col - col;
249
250
if (DDR_GET_VAL(val, DDR_BANK8, DDR_BANK8_SHIFT))
251
bank = 8; /* 8 banks */
252
else
253
bank = 4; /* 4 banks */
254
255
memsize = cs * (1 << (col+row)) * bank * dpath;
256
memsize = chip_11_errata(memsize);
257
dt_fixup_memory(0, memsize);
258
}
259
260
#define SPRN_DBCR0_40X 0x3F2
261
#define SPRN_DBCR0_44X 0x134
262
#define DBCR0_RST_SYSTEM 0x30000000
263
264
void ibm44x_dbcr_reset(void)
265
{
266
unsigned long tmp;
267
268
asm volatile (
269
"mfspr %0,%1\n"
270
"oris %0,%0,%2@h\n"
271
"mtspr %1,%0"
272
: "=&r"(tmp) : "i"(SPRN_DBCR0_44X), "i"(DBCR0_RST_SYSTEM)
273
);
274
275
}
276
277
void ibm40x_dbcr_reset(void)
278
{
279
unsigned long tmp;
280
281
asm volatile (
282
"mfspr %0,%1\n"
283
"oris %0,%0,%2@h\n"
284
"mtspr %1,%0"
285
: "=&r"(tmp) : "i"(SPRN_DBCR0_40X), "i"(DBCR0_RST_SYSTEM)
286
);
287
}
288
289
#define EMAC_RESET 0x20000000
290
void ibm4xx_quiesce_eth(u32 *emac0, u32 *emac1)
291
{
292
/* Quiesce the MAL and EMAC(s) since PIBS/OpenBIOS don't
293
* do this for us
294
*/
295
if (emac0)
296
*emac0 = EMAC_RESET;
297
if (emac1)
298
*emac1 = EMAC_RESET;
299
300
mtdcr(DCRN_MAL0_CFG, MAL_RESET);
301
while (mfdcr(DCRN_MAL0_CFG) & MAL_RESET)
302
; /* loop until reset takes effect */
303
}
304
305
/* Read 4xx EBC bus bridge registers to get mappings of the peripheral
306
* banks into the OPB address space */
307
void ibm4xx_fixup_ebc_ranges(const char *ebc)
308
{
309
void *devp;
310
u32 bxcr;
311
u32 ranges[EBC_NUM_BANKS*4];
312
u32 *p = ranges;
313
int i;
314
315
for (i = 0; i < EBC_NUM_BANKS; i++) {
316
mtdcr(DCRN_EBC0_CFGADDR, EBC_BXCR(i));
317
bxcr = mfdcr(DCRN_EBC0_CFGDATA);
318
319
if ((bxcr & EBC_BXCR_BU) != EBC_BXCR_BU_OFF) {
320
*p++ = i;
321
*p++ = 0;
322
*p++ = bxcr & EBC_BXCR_BAS;
323
*p++ = EBC_BXCR_BANK_SIZE(bxcr);
324
}
325
}
326
327
devp = finddevice(ebc);
328
if (! devp)
329
fatal("Couldn't locate EBC node %s\n\r", ebc);
330
331
setprop(devp, "ranges", ranges, (p - ranges) * sizeof(u32));
332
}
333
334
/* Calculate 440GP clocks */
335
void ibm440gp_fixup_clocks(unsigned int sys_clk, unsigned int ser_clk)
336
{
337
u32 sys0 = mfdcr(DCRN_CPC0_SYS0);
338
u32 cr0 = mfdcr(DCRN_CPC0_CR0);
339
u32 cpu, plb, opb, ebc, tb, uart0, uart1, m;
340
u32 opdv = CPC0_SYS0_OPDV(sys0);
341
u32 epdv = CPC0_SYS0_EPDV(sys0);
342
343
if (sys0 & CPC0_SYS0_BYPASS) {
344
/* Bypass system PLL */
345
cpu = plb = sys_clk;
346
} else {
347
if (sys0 & CPC0_SYS0_EXTSL)
348
/* PerClk */
349
m = CPC0_SYS0_FWDVB(sys0) * opdv * epdv;
350
else
351
/* CPU clock */
352
m = CPC0_SYS0_FBDV(sys0) * CPC0_SYS0_FWDVA(sys0);
353
cpu = sys_clk * m / CPC0_SYS0_FWDVA(sys0);
354
plb = sys_clk * m / CPC0_SYS0_FWDVB(sys0);
355
}
356
357
opb = plb / opdv;
358
ebc = opb / epdv;
359
360
/* FIXME: Check if this is for all 440GP, or just Ebony */
361
if ((mfpvr() & 0xf0000fff) == 0x40000440)
362
/* Rev. B 440GP, use external system clock */
363
tb = sys_clk;
364
else
365
/* Rev. C 440GP, errata force us to use internal clock */
366
tb = cpu;
367
368
if (cr0 & CPC0_CR0_U0EC)
369
/* External UART clock */
370
uart0 = ser_clk;
371
else
372
/* Internal UART clock */
373
uart0 = plb / CPC0_CR0_UDIV(cr0);
374
375
if (cr0 & CPC0_CR0_U1EC)
376
/* External UART clock */
377
uart1 = ser_clk;
378
else
379
/* Internal UART clock */
380
uart1 = plb / CPC0_CR0_UDIV(cr0);
381
382
printf("PPC440GP: SysClk = %dMHz (%x)\n\r",
383
(sys_clk + 500000) / 1000000, sys_clk);
384
385
dt_fixup_cpu_clocks(cpu, tb, 0);
386
387
dt_fixup_clock("/plb", plb);
388
dt_fixup_clock("/plb/opb", opb);
389
dt_fixup_clock("/plb/opb/ebc", ebc);
390
dt_fixup_clock("/plb/opb/serial@40000200", uart0);
391
dt_fixup_clock("/plb/opb/serial@40000300", uart1);
392
}
393
394
#define SPRN_CCR1 0x378
395
396
static inline u32 __fix_zero(u32 v, u32 def)
397
{
398
return v ? v : def;
399
}
400
401
static unsigned int __ibm440eplike_fixup_clocks(unsigned int sys_clk,
402
unsigned int tmr_clk,
403
int per_clk_from_opb)
404
{
405
/* PLL config */
406
u32 pllc = CPR0_READ(DCRN_CPR0_PLLC);
407
u32 plld = CPR0_READ(DCRN_CPR0_PLLD);
408
409
/* Dividers */
410
u32 fbdv = __fix_zero((plld >> 24) & 0x1f, 32);
411
u32 fwdva = __fix_zero((plld >> 16) & 0xf, 16);
412
u32 fwdvb = __fix_zero((plld >> 8) & 7, 8);
413
u32 lfbdv = __fix_zero(plld & 0x3f, 64);
414
u32 pradv0 = __fix_zero((CPR0_READ(DCRN_CPR0_PRIMAD) >> 24) & 7, 8);
415
u32 prbdv0 = __fix_zero((CPR0_READ(DCRN_CPR0_PRIMBD) >> 24) & 7, 8);
416
u32 opbdv0 = __fix_zero((CPR0_READ(DCRN_CPR0_OPBD) >> 24) & 3, 4);
417
u32 perdv0 = __fix_zero((CPR0_READ(DCRN_CPR0_PERD) >> 24) & 3, 4);
418
419
/* Input clocks for primary dividers */
420
u32 clk_a, clk_b;
421
422
/* Resulting clocks */
423
u32 cpu, plb, opb, ebc, vco;
424
425
/* Timebase */
426
u32 ccr1, tb = tmr_clk;
427
428
if (pllc & 0x40000000) {
429
u32 m;
430
431
/* Feedback path */
432
switch ((pllc >> 24) & 7) {
433
case 0:
434
/* PLLOUTx */
435
m = ((pllc & 0x20000000) ? fwdvb : fwdva) * lfbdv;
436
break;
437
case 1:
438
/* CPU */
439
m = fwdva * pradv0;
440
break;
441
case 5:
442
/* PERClk */
443
m = fwdvb * prbdv0 * opbdv0 * perdv0;
444
break;
445
default:
446
printf("WARNING ! Invalid PLL feedback source !\n");
447
goto bypass;
448
}
449
m *= fbdv;
450
vco = sys_clk * m;
451
clk_a = vco / fwdva;
452
clk_b = vco / fwdvb;
453
} else {
454
bypass:
455
/* Bypass system PLL */
456
vco = 0;
457
clk_a = clk_b = sys_clk;
458
}
459
460
cpu = clk_a / pradv0;
461
plb = clk_b / prbdv0;
462
opb = plb / opbdv0;
463
ebc = (per_clk_from_opb ? opb : plb) / perdv0;
464
465
/* Figure out timebase. Either CPU or default TmrClk */
466
ccr1 = mfspr(SPRN_CCR1);
467
468
/* If passed a 0 tmr_clk, force CPU clock */
469
if (tb == 0) {
470
ccr1 &= ~0x80u;
471
mtspr(SPRN_CCR1, ccr1);
472
}
473
if ((ccr1 & 0x0080) == 0)
474
tb = cpu;
475
476
dt_fixup_cpu_clocks(cpu, tb, 0);
477
dt_fixup_clock("/plb", plb);
478
dt_fixup_clock("/plb/opb", opb);
479
dt_fixup_clock("/plb/opb/ebc", ebc);
480
481
return plb;
482
}
483
484
static void eplike_fixup_uart_clk(int index, const char *path,
485
unsigned int ser_clk,
486
unsigned int plb_clk)
487
{
488
unsigned int sdr;
489
unsigned int clock;
490
491
switch (index) {
492
case 0:
493
sdr = SDR0_READ(DCRN_SDR0_UART0);
494
break;
495
case 1:
496
sdr = SDR0_READ(DCRN_SDR0_UART1);
497
break;
498
case 2:
499
sdr = SDR0_READ(DCRN_SDR0_UART2);
500
break;
501
case 3:
502
sdr = SDR0_READ(DCRN_SDR0_UART3);
503
break;
504
default:
505
return;
506
}
507
508
if (sdr & 0x00800000u)
509
clock = ser_clk;
510
else
511
clock = plb_clk / __fix_zero(sdr & 0xff, 256);
512
513
dt_fixup_clock(path, clock);
514
}
515
516
void ibm440ep_fixup_clocks(unsigned int sys_clk,
517
unsigned int ser_clk,
518
unsigned int tmr_clk)
519
{
520
unsigned int plb_clk = __ibm440eplike_fixup_clocks(sys_clk, tmr_clk, 0);
521
522
/* serial clocks need fixup based on int/ext */
523
eplike_fixup_uart_clk(0, "/plb/opb/serial@ef600300", ser_clk, plb_clk);
524
eplike_fixup_uart_clk(1, "/plb/opb/serial@ef600400", ser_clk, plb_clk);
525
eplike_fixup_uart_clk(2, "/plb/opb/serial@ef600500", ser_clk, plb_clk);
526
eplike_fixup_uart_clk(3, "/plb/opb/serial@ef600600", ser_clk, plb_clk);
527
}
528
529
void ibm440gx_fixup_clocks(unsigned int sys_clk,
530
unsigned int ser_clk,
531
unsigned int tmr_clk)
532
{
533
unsigned int plb_clk = __ibm440eplike_fixup_clocks(sys_clk, tmr_clk, 1);
534
535
/* serial clocks need fixup based on int/ext */
536
eplike_fixup_uart_clk(0, "/plb/opb/serial@40000200", ser_clk, plb_clk);
537
eplike_fixup_uart_clk(1, "/plb/opb/serial@40000300", ser_clk, plb_clk);
538
}
539
540
void ibm440spe_fixup_clocks(unsigned int sys_clk,
541
unsigned int ser_clk,
542
unsigned int tmr_clk)
543
{
544
unsigned int plb_clk = __ibm440eplike_fixup_clocks(sys_clk, tmr_clk, 1);
545
546
/* serial clocks need fixup based on int/ext */
547
eplike_fixup_uart_clk(0, "/plb/opb/serial@f0000200", ser_clk, plb_clk);
548
eplike_fixup_uart_clk(1, "/plb/opb/serial@f0000300", ser_clk, plb_clk);
549
eplike_fixup_uart_clk(2, "/plb/opb/serial@f0000600", ser_clk, plb_clk);
550
}
551
552
void ibm405gp_fixup_clocks(unsigned int sys_clk, unsigned int ser_clk)
553
{
554
u32 pllmr = mfdcr(DCRN_CPC0_PLLMR);
555
u32 cpc0_cr0 = mfdcr(DCRN_405_CPC0_CR0);
556
u32 cpc0_cr1 = mfdcr(DCRN_405_CPC0_CR1);
557
u32 psr = mfdcr(DCRN_405_CPC0_PSR);
558
u32 cpu, plb, opb, ebc, tb, uart0, uart1, m;
559
u32 fwdv, fwdvb, fbdv, cbdv, opdv, epdv, ppdv, udiv;
560
561
fwdv = (8 - ((pllmr & 0xe0000000) >> 29));
562
fbdv = (pllmr & 0x1e000000) >> 25;
563
if (fbdv == 0)
564
fbdv = 16;
565
cbdv = ((pllmr & 0x00060000) >> 17) + 1; /* CPU:PLB */
566
opdv = ((pllmr & 0x00018000) >> 15) + 1; /* PLB:OPB */
567
ppdv = ((pllmr & 0x00001800) >> 13) + 1; /* PLB:PCI */
568
epdv = ((pllmr & 0x00001800) >> 11) + 2; /* PLB:EBC */
569
udiv = ((cpc0_cr0 & 0x3e) >> 1) + 1;
570
571
/* check for 405GPr */
572
if ((mfpvr() & 0xfffffff0) == (0x50910951 & 0xfffffff0)) {
573
fwdvb = 8 - (pllmr & 0x00000007);
574
if (!(psr & 0x00001000)) /* PCI async mode enable == 0 */
575
if (psr & 0x00000020) /* New mode enable */
576
m = fwdvb * 2 * ppdv;
577
else
578
m = fwdvb * cbdv * ppdv;
579
else if (psr & 0x00000020) /* New mode enable */
580
if (psr & 0x00000800) /* PerClk synch mode */
581
m = fwdvb * 2 * epdv;
582
else
583
m = fbdv * fwdv;
584
else if (epdv == fbdv)
585
m = fbdv * cbdv * epdv;
586
else
587
m = fbdv * fwdvb * cbdv;
588
589
cpu = sys_clk * m / fwdv;
590
plb = sys_clk * m / (fwdvb * cbdv);
591
} else {
592
m = fwdv * fbdv * cbdv;
593
cpu = sys_clk * m / fwdv;
594
plb = cpu / cbdv;
595
}
596
opb = plb / opdv;
597
ebc = plb / epdv;
598
599
if (cpc0_cr0 & 0x80)
600
/* uart0 uses the external clock */
601
uart0 = ser_clk;
602
else
603
uart0 = cpu / udiv;
604
605
if (cpc0_cr0 & 0x40)
606
/* uart1 uses the external clock */
607
uart1 = ser_clk;
608
else
609
uart1 = cpu / udiv;
610
611
/* setup the timebase clock to tick at the cpu frequency */
612
cpc0_cr1 = cpc0_cr1 & ~0x00800000;
613
mtdcr(DCRN_405_CPC0_CR1, cpc0_cr1);
614
tb = cpu;
615
616
dt_fixup_cpu_clocks(cpu, tb, 0);
617
dt_fixup_clock("/plb", plb);
618
dt_fixup_clock("/plb/opb", opb);
619
dt_fixup_clock("/plb/ebc", ebc);
620
dt_fixup_clock("/plb/opb/serial@ef600300", uart0);
621
dt_fixup_clock("/plb/opb/serial@ef600400", uart1);
622
}
623
624
625
void ibm405ep_fixup_clocks(unsigned int sys_clk)
626
{
627
u32 pllmr0 = mfdcr(DCRN_CPC0_PLLMR0);
628
u32 pllmr1 = mfdcr(DCRN_CPC0_PLLMR1);
629
u32 cpc0_ucr = mfdcr(DCRN_CPC0_UCR);
630
u32 cpu, plb, opb, ebc, uart0, uart1;
631
u32 fwdva, fwdvb, fbdv, cbdv, opdv, epdv;
632
u32 pllmr0_ccdv, tb, m;
633
634
fwdva = 8 - ((pllmr1 & 0x00070000) >> 16);
635
fwdvb = 8 - ((pllmr1 & 0x00007000) >> 12);
636
fbdv = (pllmr1 & 0x00f00000) >> 20;
637
if (fbdv == 0)
638
fbdv = 16;
639
640
cbdv = ((pllmr0 & 0x00030000) >> 16) + 1; /* CPU:PLB */
641
epdv = ((pllmr0 & 0x00000300) >> 8) + 2; /* PLB:EBC */
642
opdv = ((pllmr0 & 0x00003000) >> 12) + 1; /* PLB:OPB */
643
644
m = fbdv * fwdvb;
645
646
pllmr0_ccdv = ((pllmr0 & 0x00300000) >> 20) + 1;
647
if (pllmr1 & 0x80000000)
648
cpu = sys_clk * m / (fwdva * pllmr0_ccdv);
649
else
650
cpu = sys_clk / pllmr0_ccdv;
651
652
plb = cpu / cbdv;
653
opb = plb / opdv;
654
ebc = plb / epdv;
655
tb = cpu;
656
uart0 = cpu / (cpc0_ucr & 0x0000007f);
657
uart1 = cpu / ((cpc0_ucr & 0x00007f00) >> 8);
658
659
dt_fixup_cpu_clocks(cpu, tb, 0);
660
dt_fixup_clock("/plb", plb);
661
dt_fixup_clock("/plb/opb", opb);
662
dt_fixup_clock("/plb/ebc", ebc);
663
dt_fixup_clock("/plb/opb/serial@ef600300", uart0);
664
dt_fixup_clock("/plb/opb/serial@ef600400", uart1);
665
}
666
667
static u8 ibm405ex_fwdv_multi_bits[] = {
668
/* values for: 1 - 16 */
669
0x01, 0x02, 0x0e, 0x09, 0x04, 0x0b, 0x10, 0x0d, 0x0c, 0x05,
670
0x06, 0x0f, 0x0a, 0x07, 0x08, 0x03
671
};
672
673
u32 ibm405ex_get_fwdva(unsigned long cpr_fwdv)
674
{
675
u32 index;
676
677
for (index = 0; index < ARRAY_SIZE(ibm405ex_fwdv_multi_bits); index++)
678
if (cpr_fwdv == (u32)ibm405ex_fwdv_multi_bits[index])
679
return index + 1;
680
681
return 0;
682
}
683
684
static u8 ibm405ex_fbdv_multi_bits[] = {
685
/* values for: 1 - 100 */
686
0x00, 0xff, 0x7e, 0xfd, 0x7a, 0xf5, 0x6a, 0xd5, 0x2a, 0xd4,
687
0x29, 0xd3, 0x26, 0xcc, 0x19, 0xb3, 0x67, 0xce, 0x1d, 0xbb,
688
0x77, 0xee, 0x5d, 0xba, 0x74, 0xe9, 0x52, 0xa5, 0x4b, 0x96,
689
0x2c, 0xd8, 0x31, 0xe3, 0x46, 0x8d, 0x1b, 0xb7, 0x6f, 0xde,
690
0x3d, 0xfb, 0x76, 0xed, 0x5a, 0xb5, 0x6b, 0xd6, 0x2d, 0xdb,
691
0x36, 0xec, 0x59, 0xb2, 0x64, 0xc9, 0x12, 0xa4, 0x48, 0x91,
692
0x23, 0xc7, 0x0e, 0x9c, 0x38, 0xf0, 0x61, 0xc2, 0x05, 0x8b,
693
0x17, 0xaf, 0x5f, 0xbe, 0x7c, 0xf9, 0x72, 0xe5, 0x4a, 0x95,
694
0x2b, 0xd7, 0x2e, 0xdc, 0x39, 0xf3, 0x66, 0xcd, 0x1a, 0xb4,
695
0x68, 0xd1, 0x22, 0xc4, 0x09, 0x93, 0x27, 0xcf, 0x1e, 0xbc,
696
/* values for: 101 - 200 */
697
0x78, 0xf1, 0x62, 0xc5, 0x0a, 0x94, 0x28, 0xd0, 0x21, 0xc3,
698
0x06, 0x8c, 0x18, 0xb0, 0x60, 0xc1, 0x02, 0x84, 0x08, 0x90,
699
0x20, 0xc0, 0x01, 0x83, 0x07, 0x8f, 0x1f, 0xbf, 0x7f, 0xfe,
700
0x7d, 0xfa, 0x75, 0xea, 0x55, 0xaa, 0x54, 0xa9, 0x53, 0xa6,
701
0x4c, 0x99, 0x33, 0xe7, 0x4e, 0x9d, 0x3b, 0xf7, 0x6e, 0xdd,
702
0x3a, 0xf4, 0x69, 0xd2, 0x25, 0xcb, 0x16, 0xac, 0x58, 0xb1,
703
0x63, 0xc6, 0x0d, 0x9b, 0x37, 0xef, 0x5e, 0xbd, 0x7b, 0xf6,
704
0x6d, 0xda, 0x35, 0xeb, 0x56, 0xad, 0x5b, 0xb6, 0x6c, 0xd9,
705
0x32, 0xe4, 0x49, 0x92, 0x24, 0xc8, 0x11, 0xa3, 0x47, 0x8e,
706
0x1c, 0xb8, 0x70, 0xe1, 0x42, 0x85, 0x0b, 0x97, 0x2f, 0xdf,
707
/* values for: 201 - 255 */
708
0x3e, 0xfc, 0x79, 0xf2, 0x65, 0xca, 0x15, 0xab, 0x57, 0xae,
709
0x5c, 0xb9, 0x73, 0xe6, 0x4d, 0x9a, 0x34, 0xe8, 0x51, 0xa2,
710
0x44, 0x89, 0x13, 0xa7, 0x4f, 0x9e, 0x3c, 0xf8, 0x71, 0xe2,
711
0x45, 0x8a, 0x14, 0xa8, 0x50, 0xa1, 0x43, 0x86, 0x0c, 0x98,
712
0x30, 0xe0, 0x41, 0x82, 0x04, 0x88, 0x10, 0xa0, 0x40, 0x81,
713
0x03, 0x87, 0x0f, 0x9f, 0x3f /* END */
714
};
715
716
u32 ibm405ex_get_fbdv(unsigned long cpr_fbdv)
717
{
718
u32 index;
719
720
for (index = 0; index < ARRAY_SIZE(ibm405ex_fbdv_multi_bits); index++)
721
if (cpr_fbdv == (u32)ibm405ex_fbdv_multi_bits[index])
722
return index + 1;
723
724
return 0;
725
}
726
727
void ibm405ex_fixup_clocks(unsigned int sys_clk, unsigned int uart_clk)
728
{
729
/* PLL config */
730
u32 pllc = CPR0_READ(DCRN_CPR0_PLLC);
731
u32 plld = CPR0_READ(DCRN_CPR0_PLLD);
732
u32 cpud = CPR0_READ(DCRN_CPR0_PRIMAD);
733
u32 plbd = CPR0_READ(DCRN_CPR0_PRIMBD);
734
u32 opbd = CPR0_READ(DCRN_CPR0_OPBD);
735
u32 perd = CPR0_READ(DCRN_CPR0_PERD);
736
737
/* Dividers */
738
u32 fbdv = ibm405ex_get_fbdv(__fix_zero((plld >> 24) & 0xff, 1));
739
740
u32 fwdva = ibm405ex_get_fwdva(__fix_zero((plld >> 16) & 0x0f, 1));
741
742
u32 cpudv0 = __fix_zero((cpud >> 24) & 7, 8);
743
744
/* PLBDV0 is hardwared to 010. */
745
u32 plbdv0 = 2;
746
u32 plb2xdv0 = __fix_zero((plbd >> 16) & 7, 8);
747
748
u32 opbdv0 = __fix_zero((opbd >> 24) & 3, 4);
749
750
u32 perdv0 = __fix_zero((perd >> 24) & 3, 4);
751
752
/* Resulting clocks */
753
u32 cpu, plb, opb, ebc, vco, tb, uart0, uart1;
754
755
/* PLL's VCO is the source for primary forward ? */
756
if (pllc & 0x40000000) {
757
u32 m;
758
759
/* Feedback path */
760
switch ((pllc >> 24) & 7) {
761
case 0:
762
/* PLLOUTx */
763
m = fbdv;
764
break;
765
case 1:
766
/* CPU */
767
m = fbdv * fwdva * cpudv0;
768
break;
769
case 5:
770
/* PERClk */
771
m = fbdv * fwdva * plb2xdv0 * plbdv0 * opbdv0 * perdv0;
772
break;
773
default:
774
printf("WARNING ! Invalid PLL feedback source !\n");
775
goto bypass;
776
}
777
778
vco = (unsigned int)(sys_clk * m);
779
} else {
780
bypass:
781
/* Bypass system PLL */
782
vco = 0;
783
}
784
785
/* CPU = VCO / ( FWDVA x CPUDV0) */
786
cpu = vco / (fwdva * cpudv0);
787
/* PLB = VCO / ( FWDVA x PLB2XDV0 x PLBDV0) */
788
plb = vco / (fwdva * plb2xdv0 * plbdv0);
789
/* OPB = PLB / OPBDV0 */
790
opb = plb / opbdv0;
791
/* EBC = OPB / PERDV0 */
792
ebc = opb / perdv0;
793
794
tb = cpu;
795
uart0 = uart1 = uart_clk;
796
797
dt_fixup_cpu_clocks(cpu, tb, 0);
798
dt_fixup_clock("/plb", plb);
799
dt_fixup_clock("/plb/opb", opb);
800
dt_fixup_clock("/plb/opb/ebc", ebc);
801
dt_fixup_clock("/plb/opb/serial@ef600200", uart0);
802
dt_fixup_clock("/plb/opb/serial@ef600300", uart1);
803
}
804
805