1/*
2 * Copyright 2007 David Gibson, IBM Corporation.
3 *
4 * Based on earlier code:
5 *   Matt Porter <mporter@kernel.crashing.org>
6 *   Copyright 2002-2005 MontaVista Software Inc.
7 *
8 *   Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
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 <tiejun.chen@windriver.com>
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
28static 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. */
48void 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
70static 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
103void 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 */
172static 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
191read_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
205void 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
264void 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
277void 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
290void 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 */
307void 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 */
335void 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
396static inline u32 __fix_zero(u32 v, u32 def)
397{
398	return v ? v : def;
399}
400
401static 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 {
454bypass:
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
484static 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
516void 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
529void 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
540void 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
552void 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
625void 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
667static 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
673u32 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
684static 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
716u32 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
727void 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 {
780bypass:
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