xref: /openbmc/linux/arch/powerpc/boot/4xx.c (revision 8dd06ef34b6e2f41b29fbf5fc1663780f2524285)
1*2874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2869680c1SJosh Boyer /*
3869680c1SJosh Boyer  * Copyright 2007 David Gibson, IBM Corporation.
4869680c1SJosh Boyer  *
5869680c1SJosh Boyer  * Based on earlier code:
6869680c1SJosh Boyer  *   Matt Porter <mporter@kernel.crashing.org>
7869680c1SJosh Boyer  *   Copyright 2002-2005 MontaVista Software Inc.
8869680c1SJosh Boyer  *
9869680c1SJosh Boyer  *   Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
10869680c1SJosh Boyer  *   Copyright (c) 2003, 2004 Zultys Technologies
11869680c1SJosh Boyer  *
120484c1dfSTiejun Chen  * Copyright (C) 2009 Wind River Systems, Inc.
130484c1dfSTiejun Chen  *   Updated for supporting PPC405EX on Kilauea.
140484c1dfSTiejun Chen  *   Tiejun Chen <tiejun.chen@windriver.com>
15869680c1SJosh Boyer  */
16869680c1SJosh Boyer #include <stddef.h>
17869680c1SJosh Boyer #include "types.h"
18869680c1SJosh Boyer #include "string.h"
19869680c1SJosh Boyer #include "stdio.h"
20869680c1SJosh Boyer #include "ops.h"
21869680c1SJosh Boyer #include "reg.h"
22869680c1SJosh Boyer #include "dcr.h"
23869680c1SJosh Boyer 
chip_11_errata(unsigned long memsize)2413c501e6SJosh Boyer static unsigned long chip_11_errata(unsigned long memsize)
2513c501e6SJosh Boyer {
2613c501e6SJosh Boyer 	unsigned long pvr;
2713c501e6SJosh Boyer 
2813c501e6SJosh Boyer 	pvr = mfpvr();
2913c501e6SJosh Boyer 
3013c501e6SJosh Boyer 	switch (pvr & 0xf0000ff0) {
3113c501e6SJosh Boyer 		case 0x40000850:
3213c501e6SJosh Boyer 		case 0x400008d0:
3313c501e6SJosh Boyer 		case 0x200008d0:
3413c501e6SJosh Boyer 			memsize -= 4096;
3513c501e6SJosh Boyer 			break;
3613c501e6SJosh Boyer 		default:
3713c501e6SJosh Boyer 			break;
3813c501e6SJosh Boyer 	}
3913c501e6SJosh Boyer 
4013c501e6SJosh Boyer 	return memsize;
4113c501e6SJosh Boyer }
4213c501e6SJosh Boyer 
43e90f3b74SJosh Boyer /* Read the 4xx SDRAM controller to get size of system memory. */
ibm4xx_sdram_fixup_memsize(void)44d23f5099SBenjamin Herrenschmidt void ibm4xx_sdram_fixup_memsize(void)
45869680c1SJosh Boyer {
46869680c1SJosh Boyer 	int i;
47869680c1SJosh Boyer 	unsigned long memsize, bank_config;
48869680c1SJosh Boyer 
49869680c1SJosh Boyer 	memsize = 0;
50869680c1SJosh Boyer 	for (i = 0; i < ARRAY_SIZE(sdram_bxcr); i++) {
51d23f5099SBenjamin Herrenschmidt 		bank_config = SDRAM0_READ(sdram_bxcr[i]);
52869680c1SJosh Boyer 		if (bank_config & SDRAM_CONFIG_BANK_ENABLE)
53869680c1SJosh Boyer 			memsize += SDRAM_CONFIG_BANK_SIZE(bank_config);
54869680c1SJosh Boyer 	}
55869680c1SJosh Boyer 
5613c501e6SJosh Boyer 	memsize = chip_11_errata(memsize);
57869680c1SJosh Boyer 	dt_fixup_memory(0, memsize);
58869680c1SJosh Boyer }
59869680c1SJosh Boyer 
60d23f5099SBenjamin Herrenschmidt /* Read the 440SPe MQ controller to get size of system memory. */
61d23f5099SBenjamin Herrenschmidt #define DCRN_MQ0_B0BAS		0x40
62d23f5099SBenjamin Herrenschmidt #define DCRN_MQ0_B1BAS		0x41
63d23f5099SBenjamin Herrenschmidt #define DCRN_MQ0_B2BAS		0x42
64d23f5099SBenjamin Herrenschmidt #define DCRN_MQ0_B3BAS		0x43
65d23f5099SBenjamin Herrenschmidt 
ibm440spe_decode_bas(u32 bas)66d23f5099SBenjamin Herrenschmidt static u64 ibm440spe_decode_bas(u32 bas)
67d23f5099SBenjamin Herrenschmidt {
68d23f5099SBenjamin Herrenschmidt 	u64 base = ((u64)(bas & 0xFFE00000u)) << 2;
69d23f5099SBenjamin Herrenschmidt 
70d23f5099SBenjamin Herrenschmidt 	/* open coded because I'm paranoid about invalid values */
71d23f5099SBenjamin Herrenschmidt 	switch ((bas >> 4) & 0xFFF) {
72d23f5099SBenjamin Herrenschmidt 	case 0:
73d23f5099SBenjamin Herrenschmidt 		return 0;
74d23f5099SBenjamin Herrenschmidt 	case 0xffc:
75d23f5099SBenjamin Herrenschmidt 		return base + 0x000800000ull;
76d23f5099SBenjamin Herrenschmidt 	case 0xff8:
77d23f5099SBenjamin Herrenschmidt 		return base + 0x001000000ull;
78d23f5099SBenjamin Herrenschmidt 	case 0xff0:
79d23f5099SBenjamin Herrenschmidt 		return base + 0x002000000ull;
80d23f5099SBenjamin Herrenschmidt 	case 0xfe0:
81d23f5099SBenjamin Herrenschmidt 		return base + 0x004000000ull;
82d23f5099SBenjamin Herrenschmidt 	case 0xfc0:
83d23f5099SBenjamin Herrenschmidt 		return base + 0x008000000ull;
84d23f5099SBenjamin Herrenschmidt 	case 0xf80:
85d23f5099SBenjamin Herrenschmidt 		return base + 0x010000000ull;
86d23f5099SBenjamin Herrenschmidt 	case 0xf00:
87d23f5099SBenjamin Herrenschmidt 		return base + 0x020000000ull;
88d23f5099SBenjamin Herrenschmidt 	case 0xe00:
89d23f5099SBenjamin Herrenschmidt 		return base + 0x040000000ull;
90d23f5099SBenjamin Herrenschmidt 	case 0xc00:
91d23f5099SBenjamin Herrenschmidt 		return base + 0x080000000ull;
92d23f5099SBenjamin Herrenschmidt 	case 0x800:
93d23f5099SBenjamin Herrenschmidt 		return base + 0x100000000ull;
94d23f5099SBenjamin Herrenschmidt 	}
95d23f5099SBenjamin Herrenschmidt 	printf("Memory BAS value 0x%08x unsupported !\n", bas);
96d23f5099SBenjamin Herrenschmidt 	return 0;
97d23f5099SBenjamin Herrenschmidt }
98d23f5099SBenjamin Herrenschmidt 
ibm440spe_fixup_memsize(void)99d23f5099SBenjamin Herrenschmidt void ibm440spe_fixup_memsize(void)
100d23f5099SBenjamin Herrenschmidt {
101d23f5099SBenjamin Herrenschmidt 	u64 banktop, memsize = 0;
102d23f5099SBenjamin Herrenschmidt 
103d23f5099SBenjamin Herrenschmidt 	/* Ultimately, we should directly construct the memory node
104d23f5099SBenjamin Herrenschmidt 	 * so we are able to handle holes in the memory address space
105d23f5099SBenjamin Herrenschmidt 	 */
106d23f5099SBenjamin Herrenschmidt 	banktop = ibm440spe_decode_bas(mfdcr(DCRN_MQ0_B0BAS));
107d23f5099SBenjamin Herrenschmidt 	if (banktop > memsize)
108d23f5099SBenjamin Herrenschmidt 		memsize = banktop;
109d23f5099SBenjamin Herrenschmidt 	banktop = ibm440spe_decode_bas(mfdcr(DCRN_MQ0_B1BAS));
110d23f5099SBenjamin Herrenschmidt 	if (banktop > memsize)
111d23f5099SBenjamin Herrenschmidt 		memsize = banktop;
112d23f5099SBenjamin Herrenschmidt 	banktop = ibm440spe_decode_bas(mfdcr(DCRN_MQ0_B2BAS));
113d23f5099SBenjamin Herrenschmidt 	if (banktop > memsize)
114d23f5099SBenjamin Herrenschmidt 		memsize = banktop;
115d23f5099SBenjamin Herrenschmidt 	banktop = ibm440spe_decode_bas(mfdcr(DCRN_MQ0_B3BAS));
116d23f5099SBenjamin Herrenschmidt 	if (banktop > memsize)
117d23f5099SBenjamin Herrenschmidt 		memsize = banktop;
118d23f5099SBenjamin Herrenschmidt 
119d23f5099SBenjamin Herrenschmidt 	dt_fixup_memory(0, memsize);
120d23f5099SBenjamin Herrenschmidt }
121d23f5099SBenjamin Herrenschmidt 
122d23f5099SBenjamin Herrenschmidt 
123606d08bcSValentine Barshak /* 4xx DDR1/2 Denali memory controller support */
124606d08bcSValentine Barshak /* DDR0 registers */
125606d08bcSValentine Barshak #define DDR0_02			2
126606d08bcSValentine Barshak #define DDR0_08			8
127606d08bcSValentine Barshak #define DDR0_10			10
128606d08bcSValentine Barshak #define DDR0_14			14
129606d08bcSValentine Barshak #define DDR0_42			42
130606d08bcSValentine Barshak #define DDR0_43			43
131606d08bcSValentine Barshak 
132606d08bcSValentine Barshak /* DDR0_02 */
133606d08bcSValentine Barshak #define DDR_START		0x1
134606d08bcSValentine Barshak #define DDR_START_SHIFT		0
135606d08bcSValentine Barshak #define DDR_MAX_CS_REG		0x3
136606d08bcSValentine Barshak #define DDR_MAX_CS_REG_SHIFT	24
137606d08bcSValentine Barshak #define DDR_MAX_COL_REG		0xf
138606d08bcSValentine Barshak #define DDR_MAX_COL_REG_SHIFT	16
139606d08bcSValentine Barshak #define DDR_MAX_ROW_REG		0xf
140606d08bcSValentine Barshak #define DDR_MAX_ROW_REG_SHIFT	8
141606d08bcSValentine Barshak /* DDR0_08 */
142606d08bcSValentine Barshak #define DDR_DDR2_MODE		0x1
143606d08bcSValentine Barshak #define DDR_DDR2_MODE_SHIFT	0
144606d08bcSValentine Barshak /* DDR0_10 */
145606d08bcSValentine Barshak #define DDR_CS_MAP		0x3
146606d08bcSValentine Barshak #define DDR_CS_MAP_SHIFT	8
147606d08bcSValentine Barshak /* DDR0_14 */
148606d08bcSValentine Barshak #define DDR_REDUC		0x1
149606d08bcSValentine Barshak #define DDR_REDUC_SHIFT		16
150606d08bcSValentine Barshak /* DDR0_42 */
151606d08bcSValentine Barshak #define DDR_APIN		0x7
152606d08bcSValentine Barshak #define DDR_APIN_SHIFT		24
153606d08bcSValentine Barshak /* DDR0_43 */
154606d08bcSValentine Barshak #define DDR_COL_SZ		0x7
155606d08bcSValentine Barshak #define DDR_COL_SZ_SHIFT	8
156606d08bcSValentine Barshak #define DDR_BANK8		0x1
157606d08bcSValentine Barshak #define DDR_BANK8_SHIFT		0
158606d08bcSValentine Barshak 
159606d08bcSValentine Barshak #define DDR_GET_VAL(val, mask, shift)	(((val) >> (shift)) & (mask))
160606d08bcSValentine Barshak 
161644e28f3SValentine Barshak /*
162644e28f3SValentine Barshak  * Some U-Boot versions set the number of chipselects to two
163644e28f3SValentine Barshak  * for Sequoia/Rainier boards while they only have one chipselect
164644e28f3SValentine Barshak  * hardwired. Hardcode the number of chipselects to one
165644e28f3SValentine Barshak  * for sequioa/rainer board models or read the actual value
166644e28f3SValentine Barshak  * from the memory controller register DDR0_10 otherwise.
167644e28f3SValentine Barshak  */
ibm4xx_denali_get_cs(void)168644e28f3SValentine Barshak static inline u32 ibm4xx_denali_get_cs(void)
169644e28f3SValentine Barshak {
170644e28f3SValentine Barshak 	void *devp;
171644e28f3SValentine Barshak 	char model[64];
172644e28f3SValentine Barshak 	u32 val, cs;
173644e28f3SValentine Barshak 
174644e28f3SValentine Barshak 	devp = finddevice("/");
175644e28f3SValentine Barshak 	if (!devp)
176644e28f3SValentine Barshak 		goto read_cs;
177644e28f3SValentine Barshak 
178644e28f3SValentine Barshak 	if (getprop(devp, "model", model, sizeof(model)) <= 0)
179644e28f3SValentine Barshak 		goto read_cs;
180644e28f3SValentine Barshak 
181644e28f3SValentine Barshak 	model[sizeof(model)-1] = 0;
182644e28f3SValentine Barshak 
183644e28f3SValentine Barshak 	if (!strcmp(model, "amcc,sequoia") ||
184644e28f3SValentine Barshak 	    !strcmp(model, "amcc,rainier"))
185644e28f3SValentine Barshak 		return 1;
186644e28f3SValentine Barshak 
187644e28f3SValentine Barshak read_cs:
188644e28f3SValentine Barshak 	/* get CS value */
189644e28f3SValentine Barshak 	val = SDRAM0_READ(DDR0_10);
190644e28f3SValentine Barshak 
191644e28f3SValentine Barshak 	val = DDR_GET_VAL(val, DDR_CS_MAP, DDR_CS_MAP_SHIFT);
192644e28f3SValentine Barshak 	cs = 0;
193644e28f3SValentine Barshak 	while (val) {
194644e28f3SValentine Barshak 		if (val & 0x1)
195644e28f3SValentine Barshak 			cs++;
196644e28f3SValentine Barshak 		val = val >> 1;
197644e28f3SValentine Barshak 	}
198644e28f3SValentine Barshak 	return cs;
199644e28f3SValentine Barshak }
200644e28f3SValentine Barshak 
ibm4xx_denali_fixup_memsize(void)201606d08bcSValentine Barshak void ibm4xx_denali_fixup_memsize(void)
202606d08bcSValentine Barshak {
203606d08bcSValentine Barshak 	u32 val, max_cs, max_col, max_row;
204606d08bcSValentine Barshak 	u32 cs, col, row, bank, dpath;
205606d08bcSValentine Barshak 	unsigned long memsize;
206606d08bcSValentine Barshak 
207d23f5099SBenjamin Herrenschmidt 	val = SDRAM0_READ(DDR0_02);
208606d08bcSValentine Barshak 	if (!DDR_GET_VAL(val, DDR_START, DDR_START_SHIFT))
209606d08bcSValentine Barshak 		fatal("DDR controller is not initialized\n");
210606d08bcSValentine Barshak 
211606d08bcSValentine Barshak 	/* get maximum cs col and row values */
212606d08bcSValentine Barshak 	max_cs  = DDR_GET_VAL(val, DDR_MAX_CS_REG, DDR_MAX_CS_REG_SHIFT);
213606d08bcSValentine Barshak 	max_col = DDR_GET_VAL(val, DDR_MAX_COL_REG, DDR_MAX_COL_REG_SHIFT);
214606d08bcSValentine Barshak 	max_row = DDR_GET_VAL(val, DDR_MAX_ROW_REG, DDR_MAX_ROW_REG_SHIFT);
215606d08bcSValentine Barshak 
216644e28f3SValentine Barshak 	cs = ibm4xx_denali_get_cs();
217606d08bcSValentine Barshak 	if (!cs)
218606d08bcSValentine Barshak 		fatal("No memory installed\n");
219606d08bcSValentine Barshak 	if (cs > max_cs)
220606d08bcSValentine Barshak 		fatal("DDR wrong CS configuration\n");
221606d08bcSValentine Barshak 
222606d08bcSValentine Barshak 	/* get data path bytes */
223d23f5099SBenjamin Herrenschmidt 	val = SDRAM0_READ(DDR0_14);
224606d08bcSValentine Barshak 
225606d08bcSValentine Barshak 	if (DDR_GET_VAL(val, DDR_REDUC, DDR_REDUC_SHIFT))
226606d08bcSValentine Barshak 		dpath = 4; /* 32 bits */
227644e28f3SValentine Barshak 	else
228644e28f3SValentine Barshak 		dpath = 8; /* 64 bits */
229606d08bcSValentine Barshak 
23000d70419Sjoe@perches.com 	/* get address pins (rows) */
231d23f5099SBenjamin Herrenschmidt 	val = SDRAM0_READ(DDR0_42);
232606d08bcSValentine Barshak 
233606d08bcSValentine Barshak 	row = DDR_GET_VAL(val, DDR_APIN, DDR_APIN_SHIFT);
234606d08bcSValentine Barshak 	if (row > max_row)
235606d08bcSValentine Barshak 		fatal("DDR wrong APIN configuration\n");
236606d08bcSValentine Barshak 	row = max_row - row;
237606d08bcSValentine Barshak 
238606d08bcSValentine Barshak 	/* get collomn size and banks */
239d23f5099SBenjamin Herrenschmidt 	val = SDRAM0_READ(DDR0_43);
240606d08bcSValentine Barshak 
241606d08bcSValentine Barshak 	col = DDR_GET_VAL(val, DDR_COL_SZ, DDR_COL_SZ_SHIFT);
242606d08bcSValentine Barshak 	if (col > max_col)
243606d08bcSValentine Barshak 		fatal("DDR wrong COL configuration\n");
244606d08bcSValentine Barshak 	col = max_col - col;
245606d08bcSValentine Barshak 
246606d08bcSValentine Barshak 	if (DDR_GET_VAL(val, DDR_BANK8, DDR_BANK8_SHIFT))
247606d08bcSValentine Barshak 		bank = 8; /* 8 banks */
248606d08bcSValentine Barshak 	else
249606d08bcSValentine Barshak 		bank = 4; /* 4 banks */
250606d08bcSValentine Barshak 
251606d08bcSValentine Barshak 	memsize = cs * (1 << (col+row)) * bank * dpath;
25213c501e6SJosh Boyer 	memsize = chip_11_errata(memsize);
253606d08bcSValentine Barshak 	dt_fixup_memory(0, memsize);
254606d08bcSValentine Barshak }
255606d08bcSValentine Barshak 
256e90f3b74SJosh Boyer #define SPRN_DBCR0_40X 0x3F2
257e90f3b74SJosh Boyer #define SPRN_DBCR0_44X 0x134
258869680c1SJosh Boyer #define DBCR0_RST_SYSTEM 0x30000000
259869680c1SJosh Boyer 
ibm44x_dbcr_reset(void)260869680c1SJosh Boyer void ibm44x_dbcr_reset(void)
261869680c1SJosh Boyer {
262869680c1SJosh Boyer 	unsigned long tmp;
263869680c1SJosh Boyer 
264869680c1SJosh Boyer 	asm volatile (
265869680c1SJosh Boyer 		"mfspr	%0,%1\n"
266869680c1SJosh Boyer 		"oris	%0,%0,%2@h\n"
267869680c1SJosh Boyer 		"mtspr	%1,%0"
268e90f3b74SJosh Boyer 		: "=&r"(tmp) : "i"(SPRN_DBCR0_44X), "i"(DBCR0_RST_SYSTEM)
269869680c1SJosh Boyer 		);
270869680c1SJosh Boyer 
271869680c1SJosh Boyer }
272869680c1SJosh Boyer 
ibm40x_dbcr_reset(void)273e90f3b74SJosh Boyer void ibm40x_dbcr_reset(void)
274e90f3b74SJosh Boyer {
275e90f3b74SJosh Boyer 	unsigned long tmp;
276e90f3b74SJosh Boyer 
277e90f3b74SJosh Boyer 	asm volatile (
278e90f3b74SJosh Boyer 		"mfspr	%0,%1\n"
279e90f3b74SJosh Boyer 		"oris	%0,%0,%2@h\n"
280e90f3b74SJosh Boyer 		"mtspr	%1,%0"
281e90f3b74SJosh Boyer 		: "=&r"(tmp) : "i"(SPRN_DBCR0_40X), "i"(DBCR0_RST_SYSTEM)
282e90f3b74SJosh Boyer 		);
283e90f3b74SJosh Boyer }
284e90f3b74SJosh Boyer 
285e90f3b74SJosh Boyer #define EMAC_RESET 0x20000000
ibm4xx_quiesce_eth(u32 * emac0,u32 * emac1)286e90f3b74SJosh Boyer void ibm4xx_quiesce_eth(u32 *emac0, u32 *emac1)
287e90f3b74SJosh Boyer {
28861974038SBenjamin Herrenschmidt 	/* Quiesce the MAL and EMAC(s) since PIBS/OpenBIOS don't
28961974038SBenjamin Herrenschmidt 	 * do this for us
29061974038SBenjamin Herrenschmidt 	 */
291e90f3b74SJosh Boyer 	if (emac0)
292e90f3b74SJosh Boyer 		*emac0 = EMAC_RESET;
293e90f3b74SJosh Boyer 	if (emac1)
294e90f3b74SJosh Boyer 		*emac1 = EMAC_RESET;
295e90f3b74SJosh Boyer 
296e90f3b74SJosh Boyer 	mtdcr(DCRN_MAL0_CFG, MAL_RESET);
29767196d72SJosh Boyer 	while (mfdcr(DCRN_MAL0_CFG) & MAL_RESET)
29867196d72SJosh Boyer 		; /* loop until reset takes effect */
299e90f3b74SJosh Boyer }
300e90f3b74SJosh Boyer 
301869680c1SJosh Boyer /* Read 4xx EBC bus bridge registers to get mappings of the peripheral
302869680c1SJosh Boyer  * banks into the OPB address space */
ibm4xx_fixup_ebc_ranges(const char * ebc)303869680c1SJosh Boyer void ibm4xx_fixup_ebc_ranges(const char *ebc)
304869680c1SJosh Boyer {
305869680c1SJosh Boyer 	void *devp;
306869680c1SJosh Boyer 	u32 bxcr;
307869680c1SJosh Boyer 	u32 ranges[EBC_NUM_BANKS*4];
308869680c1SJosh Boyer 	u32 *p = ranges;
309869680c1SJosh Boyer 	int i;
310869680c1SJosh Boyer 
311869680c1SJosh Boyer 	for (i = 0; i < EBC_NUM_BANKS; i++) {
312869680c1SJosh Boyer 		mtdcr(DCRN_EBC0_CFGADDR, EBC_BXCR(i));
313869680c1SJosh Boyer 		bxcr = mfdcr(DCRN_EBC0_CFGDATA);
314869680c1SJosh Boyer 
315869680c1SJosh Boyer 		if ((bxcr & EBC_BXCR_BU) != EBC_BXCR_BU_OFF) {
316869680c1SJosh Boyer 			*p++ = i;
317869680c1SJosh Boyer 			*p++ = 0;
318869680c1SJosh Boyer 			*p++ = bxcr & EBC_BXCR_BAS;
319869680c1SJosh Boyer 			*p++ = EBC_BXCR_BANK_SIZE(bxcr);
320869680c1SJosh Boyer 		}
321869680c1SJosh Boyer 	}
322869680c1SJosh Boyer 
323869680c1SJosh Boyer 	devp = finddevice(ebc);
324869680c1SJosh Boyer 	if (! devp)
325869680c1SJosh Boyer 		fatal("Couldn't locate EBC node %s\n\r", ebc);
326869680c1SJosh Boyer 
327869680c1SJosh Boyer 	setprop(devp, "ranges", ranges, (p - ranges) * sizeof(u32));
328869680c1SJosh Boyer }
3292ba4573cSJosh Boyer 
330190de005SBenjamin Herrenschmidt /* Calculate 440GP clocks */
ibm440gp_fixup_clocks(unsigned int sys_clk,unsigned int ser_clk)331190de005SBenjamin Herrenschmidt void ibm440gp_fixup_clocks(unsigned int sys_clk, unsigned int ser_clk)
3322ba4573cSJosh Boyer {
333190de005SBenjamin Herrenschmidt 	u32 sys0 = mfdcr(DCRN_CPC0_SYS0);
334190de005SBenjamin Herrenschmidt 	u32 cr0 = mfdcr(DCRN_CPC0_CR0);
335190de005SBenjamin Herrenschmidt 	u32 cpu, plb, opb, ebc, tb, uart0, uart1, m;
336190de005SBenjamin Herrenschmidt 	u32 opdv = CPC0_SYS0_OPDV(sys0);
337190de005SBenjamin Herrenschmidt 	u32 epdv = CPC0_SYS0_EPDV(sys0);
3382ba4573cSJosh Boyer 
339190de005SBenjamin Herrenschmidt 	if (sys0 & CPC0_SYS0_BYPASS) {
340190de005SBenjamin Herrenschmidt 		/* Bypass system PLL */
341190de005SBenjamin Herrenschmidt 		cpu = plb = sys_clk;
342190de005SBenjamin Herrenschmidt 	} else {
343190de005SBenjamin Herrenschmidt 		if (sys0 & CPC0_SYS0_EXTSL)
344190de005SBenjamin Herrenschmidt 			/* PerClk */
345190de005SBenjamin Herrenschmidt 			m = CPC0_SYS0_FWDVB(sys0) * opdv * epdv;
3462ba4573cSJosh Boyer 		else
347190de005SBenjamin Herrenschmidt 			/* CPU clock */
348190de005SBenjamin Herrenschmidt 			m = CPC0_SYS0_FBDV(sys0) * CPC0_SYS0_FWDVA(sys0);
349190de005SBenjamin Herrenschmidt 		cpu = sys_clk * m / CPC0_SYS0_FWDVA(sys0);
350190de005SBenjamin Herrenschmidt 		plb = sys_clk * m / CPC0_SYS0_FWDVB(sys0);
3512ba4573cSJosh Boyer 	}
352190de005SBenjamin Herrenschmidt 
353190de005SBenjamin Herrenschmidt 	opb = plb / opdv;
354190de005SBenjamin Herrenschmidt 	ebc = opb / epdv;
355190de005SBenjamin Herrenschmidt 
356190de005SBenjamin Herrenschmidt 	/* FIXME: Check if this is for all 440GP, or just Ebony */
357190de005SBenjamin Herrenschmidt 	if ((mfpvr() & 0xf0000fff) == 0x40000440)
358190de005SBenjamin Herrenschmidt 		/* Rev. B 440GP, use external system clock */
359190de005SBenjamin Herrenschmidt 		tb = sys_clk;
3602ba4573cSJosh Boyer 	else
361190de005SBenjamin Herrenschmidt 		/* Rev. C 440GP, errata force us to use internal clock */
362190de005SBenjamin Herrenschmidt 		tb = cpu;
3632ba4573cSJosh Boyer 
364190de005SBenjamin Herrenschmidt 	if (cr0 & CPC0_CR0_U0EC)
365190de005SBenjamin Herrenschmidt 		/* External UART clock */
3662ba4573cSJosh Boyer 		uart0 = ser_clk;
367190de005SBenjamin Herrenschmidt 	else
368190de005SBenjamin Herrenschmidt 		/* Internal UART clock */
369190de005SBenjamin Herrenschmidt 		uart0 = plb / CPC0_CR0_UDIV(cr0);
370190de005SBenjamin Herrenschmidt 
371190de005SBenjamin Herrenschmidt 	if (cr0 & CPC0_CR0_U1EC)
372190de005SBenjamin Herrenschmidt 		/* External UART clock */
373190de005SBenjamin Herrenschmidt 		uart1 = ser_clk;
374190de005SBenjamin Herrenschmidt 	else
375190de005SBenjamin Herrenschmidt 		/* Internal UART clock */
376190de005SBenjamin Herrenschmidt 		uart1 = plb / CPC0_CR0_UDIV(cr0);
377190de005SBenjamin Herrenschmidt 
378190de005SBenjamin Herrenschmidt 	printf("PPC440GP: SysClk = %dMHz (%x)\n\r",
379190de005SBenjamin Herrenschmidt 	       (sys_clk + 500000) / 1000000, sys_clk);
380190de005SBenjamin Herrenschmidt 
381190de005SBenjamin Herrenschmidt 	dt_fixup_cpu_clocks(cpu, tb, 0);
382190de005SBenjamin Herrenschmidt 
383190de005SBenjamin Herrenschmidt 	dt_fixup_clock("/plb", plb);
384190de005SBenjamin Herrenschmidt 	dt_fixup_clock("/plb/opb", opb);
385190de005SBenjamin Herrenschmidt 	dt_fixup_clock("/plb/opb/ebc", ebc);
386190de005SBenjamin Herrenschmidt 	dt_fixup_clock("/plb/opb/serial@40000200", uart0);
387190de005SBenjamin Herrenschmidt 	dt_fixup_clock("/plb/opb/serial@40000300", uart1);
388190de005SBenjamin Herrenschmidt }
389190de005SBenjamin Herrenschmidt 
390190de005SBenjamin Herrenschmidt #define SPRN_CCR1 0x378
391190de005SBenjamin Herrenschmidt 
__fix_zero(u32 v,u32 def)392190de005SBenjamin Herrenschmidt static inline u32 __fix_zero(u32 v, u32 def)
393190de005SBenjamin Herrenschmidt {
394190de005SBenjamin Herrenschmidt 	return v ? v : def;
395190de005SBenjamin Herrenschmidt }
396190de005SBenjamin Herrenschmidt 
__ibm440eplike_fixup_clocks(unsigned int sys_clk,unsigned int tmr_clk,int per_clk_from_opb)397190de005SBenjamin Herrenschmidt static unsigned int __ibm440eplike_fixup_clocks(unsigned int sys_clk,
398190de005SBenjamin Herrenschmidt 						unsigned int tmr_clk,
399190de005SBenjamin Herrenschmidt 						int per_clk_from_opb)
400190de005SBenjamin Herrenschmidt {
401190de005SBenjamin Herrenschmidt 	/* PLL config */
402190de005SBenjamin Herrenschmidt 	u32 pllc  = CPR0_READ(DCRN_CPR0_PLLC);
403190de005SBenjamin Herrenschmidt 	u32 plld  = CPR0_READ(DCRN_CPR0_PLLD);
404190de005SBenjamin Herrenschmidt 
405190de005SBenjamin Herrenschmidt 	/* Dividers */
406190de005SBenjamin Herrenschmidt 	u32 fbdv   = __fix_zero((plld >> 24) & 0x1f, 32);
407190de005SBenjamin Herrenschmidt 	u32 fwdva  = __fix_zero((plld >> 16) & 0xf, 16);
408190de005SBenjamin Herrenschmidt 	u32 fwdvb  = __fix_zero((plld >> 8) & 7, 8);
409190de005SBenjamin Herrenschmidt 	u32 lfbdv  = __fix_zero(plld & 0x3f, 64);
410190de005SBenjamin Herrenschmidt 	u32 pradv0 = __fix_zero((CPR0_READ(DCRN_CPR0_PRIMAD) >> 24) & 7, 8);
411190de005SBenjamin Herrenschmidt 	u32 prbdv0 = __fix_zero((CPR0_READ(DCRN_CPR0_PRIMBD) >> 24) & 7, 8);
412190de005SBenjamin Herrenschmidt 	u32 opbdv0 = __fix_zero((CPR0_READ(DCRN_CPR0_OPBD) >> 24) & 3, 4);
413190de005SBenjamin Herrenschmidt 	u32 perdv0 = __fix_zero((CPR0_READ(DCRN_CPR0_PERD) >> 24) & 3, 4);
414190de005SBenjamin Herrenschmidt 
415190de005SBenjamin Herrenschmidt 	/* Input clocks for primary dividers */
416190de005SBenjamin Herrenschmidt 	u32 clk_a, clk_b;
417190de005SBenjamin Herrenschmidt 
418190de005SBenjamin Herrenschmidt 	/* Resulting clocks */
419190de005SBenjamin Herrenschmidt 	u32 cpu, plb, opb, ebc, vco;
420190de005SBenjamin Herrenschmidt 
421190de005SBenjamin Herrenschmidt 	/* Timebase */
422190de005SBenjamin Herrenschmidt 	u32 ccr1, tb = tmr_clk;
423190de005SBenjamin Herrenschmidt 
424190de005SBenjamin Herrenschmidt 	if (pllc & 0x40000000) {
425190de005SBenjamin Herrenschmidt 		u32 m;
426190de005SBenjamin Herrenschmidt 
427190de005SBenjamin Herrenschmidt 		/* Feedback path */
428190de005SBenjamin Herrenschmidt 		switch ((pllc >> 24) & 7) {
429190de005SBenjamin Herrenschmidt 		case 0:
430190de005SBenjamin Herrenschmidt 			/* PLLOUTx */
431190de005SBenjamin Herrenschmidt 			m = ((pllc & 0x20000000) ? fwdvb : fwdva) * lfbdv;
432190de005SBenjamin Herrenschmidt 			break;
433190de005SBenjamin Herrenschmidt 		case 1:
434190de005SBenjamin Herrenschmidt 			/* CPU */
435190de005SBenjamin Herrenschmidt 			m = fwdva * pradv0;
436190de005SBenjamin Herrenschmidt 			break;
437190de005SBenjamin Herrenschmidt 		case 5:
438190de005SBenjamin Herrenschmidt 			/* PERClk */
439190de005SBenjamin Herrenschmidt 			m = fwdvb * prbdv0 * opbdv0 * perdv0;
440190de005SBenjamin Herrenschmidt 			break;
441190de005SBenjamin Herrenschmidt 		default:
442190de005SBenjamin Herrenschmidt 			printf("WARNING ! Invalid PLL feedback source !\n");
443190de005SBenjamin Herrenschmidt 			goto bypass;
444190de005SBenjamin Herrenschmidt 		}
445190de005SBenjamin Herrenschmidt 		m *= fbdv;
446190de005SBenjamin Herrenschmidt 		vco = sys_clk * m;
447190de005SBenjamin Herrenschmidt 		clk_a = vco / fwdva;
448190de005SBenjamin Herrenschmidt 		clk_b = vco / fwdvb;
449190de005SBenjamin Herrenschmidt 	} else {
450190de005SBenjamin Herrenschmidt bypass:
451190de005SBenjamin Herrenschmidt 		/* Bypass system PLL */
452190de005SBenjamin Herrenschmidt 		vco = 0;
453190de005SBenjamin Herrenschmidt 		clk_a = clk_b = sys_clk;
454190de005SBenjamin Herrenschmidt 	}
455190de005SBenjamin Herrenschmidt 
456190de005SBenjamin Herrenschmidt 	cpu = clk_a / pradv0;
457190de005SBenjamin Herrenschmidt 	plb = clk_b / prbdv0;
458190de005SBenjamin Herrenschmidt 	opb = plb / opbdv0;
459190de005SBenjamin Herrenschmidt 	ebc = (per_clk_from_opb ? opb : plb) / perdv0;
4602ba4573cSJosh Boyer 
4612ba4573cSJosh Boyer 	/* Figure out timebase.  Either CPU or default TmrClk */
462190de005SBenjamin Herrenschmidt 	ccr1 = mfspr(SPRN_CCR1);
463190de005SBenjamin Herrenschmidt 
464190de005SBenjamin Herrenschmidt 	/* If passed a 0 tmr_clk, force CPU clock */
465190de005SBenjamin Herrenschmidt 	if (tb == 0) {
466190de005SBenjamin Herrenschmidt 		ccr1 &= ~0x80u;
467190de005SBenjamin Herrenschmidt 		mtspr(SPRN_CCR1, ccr1);
468190de005SBenjamin Herrenschmidt 	}
469190de005SBenjamin Herrenschmidt 	if ((ccr1 & 0x0080) == 0)
4702ba4573cSJosh Boyer 		tb = cpu;
4712ba4573cSJosh Boyer 
4722ba4573cSJosh Boyer 	dt_fixup_cpu_clocks(cpu, tb, 0);
4732ba4573cSJosh Boyer 	dt_fixup_clock("/plb", plb);
4742ba4573cSJosh Boyer 	dt_fixup_clock("/plb/opb", opb);
4752ba4573cSJosh Boyer 	dt_fixup_clock("/plb/opb/ebc", ebc);
476190de005SBenjamin Herrenschmidt 
477190de005SBenjamin Herrenschmidt 	return plb;
4782ba4573cSJosh Boyer }
47961974038SBenjamin Herrenschmidt 
eplike_fixup_uart_clk(int index,const char * path,unsigned int ser_clk,unsigned int plb_clk)480190de005SBenjamin Herrenschmidt static void eplike_fixup_uart_clk(int index, const char *path,
481190de005SBenjamin Herrenschmidt 				  unsigned int ser_clk,
482190de005SBenjamin Herrenschmidt 				  unsigned int plb_clk)
483190de005SBenjamin Herrenschmidt {
484190de005SBenjamin Herrenschmidt 	unsigned int sdr;
485190de005SBenjamin Herrenschmidt 	unsigned int clock;
486190de005SBenjamin Herrenschmidt 
487190de005SBenjamin Herrenschmidt 	switch (index) {
488190de005SBenjamin Herrenschmidt 	case 0:
489190de005SBenjamin Herrenschmidt 		sdr = SDR0_READ(DCRN_SDR0_UART0);
490190de005SBenjamin Herrenschmidt 		break;
491190de005SBenjamin Herrenschmidt 	case 1:
492190de005SBenjamin Herrenschmidt 		sdr = SDR0_READ(DCRN_SDR0_UART1);
493190de005SBenjamin Herrenschmidt 		break;
494190de005SBenjamin Herrenschmidt 	case 2:
495190de005SBenjamin Herrenschmidt 		sdr = SDR0_READ(DCRN_SDR0_UART2);
496190de005SBenjamin Herrenschmidt 		break;
497190de005SBenjamin Herrenschmidt 	case 3:
498190de005SBenjamin Herrenschmidt 		sdr = SDR0_READ(DCRN_SDR0_UART3);
499190de005SBenjamin Herrenschmidt 		break;
500190de005SBenjamin Herrenschmidt 	default:
501190de005SBenjamin Herrenschmidt 		return;
502190de005SBenjamin Herrenschmidt 	}
503190de005SBenjamin Herrenschmidt 
504190de005SBenjamin Herrenschmidt 	if (sdr & 0x00800000u)
505190de005SBenjamin Herrenschmidt 		clock = ser_clk;
506190de005SBenjamin Herrenschmidt 	else
507190de005SBenjamin Herrenschmidt 		clock = plb_clk / __fix_zero(sdr & 0xff, 256);
508190de005SBenjamin Herrenschmidt 
509190de005SBenjamin Herrenschmidt 	dt_fixup_clock(path, clock);
510190de005SBenjamin Herrenschmidt }
511190de005SBenjamin Herrenschmidt 
ibm440ep_fixup_clocks(unsigned int sys_clk,unsigned int ser_clk,unsigned int tmr_clk)512190de005SBenjamin Herrenschmidt void ibm440ep_fixup_clocks(unsigned int sys_clk,
513190de005SBenjamin Herrenschmidt 			   unsigned int ser_clk,
514190de005SBenjamin Herrenschmidt 			   unsigned int tmr_clk)
515190de005SBenjamin Herrenschmidt {
516190de005SBenjamin Herrenschmidt 	unsigned int plb_clk = __ibm440eplike_fixup_clocks(sys_clk, tmr_clk, 0);
517190de005SBenjamin Herrenschmidt 
51858645c7fSBenjamin Herrenschmidt 	/* serial clocks need fixup based on int/ext */
519190de005SBenjamin Herrenschmidt 	eplike_fixup_uart_clk(0, "/plb/opb/serial@ef600300", ser_clk, plb_clk);
520190de005SBenjamin Herrenschmidt 	eplike_fixup_uart_clk(1, "/plb/opb/serial@ef600400", ser_clk, plb_clk);
521190de005SBenjamin Herrenschmidt 	eplike_fixup_uart_clk(2, "/plb/opb/serial@ef600500", ser_clk, plb_clk);
522190de005SBenjamin Herrenschmidt 	eplike_fixup_uart_clk(3, "/plb/opb/serial@ef600600", ser_clk, plb_clk);
523190de005SBenjamin Herrenschmidt }
524190de005SBenjamin Herrenschmidt 
ibm440gx_fixup_clocks(unsigned int sys_clk,unsigned int ser_clk,unsigned int tmr_clk)525190de005SBenjamin Herrenschmidt void ibm440gx_fixup_clocks(unsigned int sys_clk,
526190de005SBenjamin Herrenschmidt 			   unsigned int ser_clk,
527190de005SBenjamin Herrenschmidt 			   unsigned int tmr_clk)
528190de005SBenjamin Herrenschmidt {
529190de005SBenjamin Herrenschmidt 	unsigned int plb_clk = __ibm440eplike_fixup_clocks(sys_clk, tmr_clk, 1);
530190de005SBenjamin Herrenschmidt 
53158645c7fSBenjamin Herrenschmidt 	/* serial clocks need fixup based on int/ext */
532190de005SBenjamin Herrenschmidt 	eplike_fixup_uart_clk(0, "/plb/opb/serial@40000200", ser_clk, plb_clk);
533190de005SBenjamin Herrenschmidt 	eplike_fixup_uart_clk(1, "/plb/opb/serial@40000300", ser_clk, plb_clk);
534190de005SBenjamin Herrenschmidt }
535190de005SBenjamin Herrenschmidt 
ibm440spe_fixup_clocks(unsigned int sys_clk,unsigned int ser_clk,unsigned int tmr_clk)536190de005SBenjamin Herrenschmidt void ibm440spe_fixup_clocks(unsigned int sys_clk,
537190de005SBenjamin Herrenschmidt 			    unsigned int ser_clk,
538190de005SBenjamin Herrenschmidt 			    unsigned int tmr_clk)
539190de005SBenjamin Herrenschmidt {
540190de005SBenjamin Herrenschmidt 	unsigned int plb_clk = __ibm440eplike_fixup_clocks(sys_clk, tmr_clk, 1);
541190de005SBenjamin Herrenschmidt 
54258645c7fSBenjamin Herrenschmidt 	/* serial clocks need fixup based on int/ext */
54358645c7fSBenjamin Herrenschmidt 	eplike_fixup_uart_clk(0, "/plb/opb/serial@f0000200", ser_clk, plb_clk);
54458645c7fSBenjamin Herrenschmidt 	eplike_fixup_uart_clk(1, "/plb/opb/serial@f0000300", ser_clk, plb_clk);
54558645c7fSBenjamin Herrenschmidt 	eplike_fixup_uart_clk(2, "/plb/opb/serial@f0000600", ser_clk, plb_clk);
546190de005SBenjamin Herrenschmidt }
547190de005SBenjamin Herrenschmidt 
ibm405gp_fixup_clocks(unsigned int sys_clk,unsigned int ser_clk)548190de005SBenjamin Herrenschmidt void ibm405gp_fixup_clocks(unsigned int sys_clk, unsigned int ser_clk)
54961974038SBenjamin Herrenschmidt {
55061974038SBenjamin Herrenschmidt 	u32 pllmr = mfdcr(DCRN_CPC0_PLLMR);
55161974038SBenjamin Herrenschmidt 	u32 cpc0_cr0 = mfdcr(DCRN_405_CPC0_CR0);
55261974038SBenjamin Herrenschmidt 	u32 cpc0_cr1 = mfdcr(DCRN_405_CPC0_CR1);
5532af59f7dSMatthias Fuchs 	u32 psr = mfdcr(DCRN_405_CPC0_PSR);
55461974038SBenjamin Herrenschmidt 	u32 cpu, plb, opb, ebc, tb, uart0, uart1, m;
5552af59f7dSMatthias Fuchs 	u32 fwdv, fwdvb, fbdv, cbdv, opdv, epdv, ppdv, udiv;
55661974038SBenjamin Herrenschmidt 
55761974038SBenjamin Herrenschmidt 	fwdv = (8 - ((pllmr & 0xe0000000) >> 29));
55861974038SBenjamin Herrenschmidt 	fbdv = (pllmr & 0x1e000000) >> 25;
5592af59f7dSMatthias Fuchs 	if (fbdv == 0)
5602af59f7dSMatthias Fuchs 		fbdv = 16;
5612af59f7dSMatthias Fuchs 	cbdv = ((pllmr & 0x00060000) >> 17) + 1; /* CPU:PLB */
5622af59f7dSMatthias Fuchs 	opdv = ((pllmr & 0x00018000) >> 15) + 1; /* PLB:OPB */
5638d046759SDan Carpenter 	ppdv = ((pllmr & 0x00006000) >> 13) + 1; /* PLB:PCI */
5642af59f7dSMatthias Fuchs 	epdv = ((pllmr & 0x00001800) >> 11) + 2; /* PLB:EBC */
56561974038SBenjamin Herrenschmidt 	udiv = ((cpc0_cr0 & 0x3e) >> 1) + 1;
56661974038SBenjamin Herrenschmidt 
5672af59f7dSMatthias Fuchs 	/* check for 405GPr */
5682af59f7dSMatthias Fuchs 	if ((mfpvr() & 0xfffffff0) == (0x50910951 & 0xfffffff0)) {
5692af59f7dSMatthias Fuchs 		fwdvb = 8 - (pllmr & 0x00000007);
5702af59f7dSMatthias Fuchs 		if (!(psr & 0x00001000)) /* PCI async mode enable == 0 */
5712af59f7dSMatthias Fuchs 			if (psr & 0x00000020) /* New mode enable */
5722af59f7dSMatthias Fuchs 				m = fwdvb * 2 * ppdv;
5732af59f7dSMatthias Fuchs 			else
5742af59f7dSMatthias Fuchs 				m = fwdvb * cbdv * ppdv;
5752af59f7dSMatthias Fuchs 		else if (psr & 0x00000020) /* New mode enable */
5762af59f7dSMatthias Fuchs 			if (psr & 0x00000800) /* PerClk synch mode */
5772af59f7dSMatthias Fuchs 				m = fwdvb * 2 * epdv;
5782af59f7dSMatthias Fuchs 			else
5792af59f7dSMatthias Fuchs 				m = fbdv * fwdv;
5802af59f7dSMatthias Fuchs 		else if (epdv == fbdv)
5812af59f7dSMatthias Fuchs 			m = fbdv * cbdv * epdv;
5822af59f7dSMatthias Fuchs 		else
5832af59f7dSMatthias Fuchs 			m = fbdv * fwdvb * cbdv;
58461974038SBenjamin Herrenschmidt 
585190de005SBenjamin Herrenschmidt 		cpu = sys_clk * m / fwdv;
5862af59f7dSMatthias Fuchs 		plb = sys_clk * m / (fwdvb * cbdv);
5872af59f7dSMatthias Fuchs 	} else {
5882af59f7dSMatthias Fuchs 		m = fwdv * fbdv * cbdv;
5892af59f7dSMatthias Fuchs 		cpu = sys_clk * m / fwdv;
59061974038SBenjamin Herrenschmidt 		plb = cpu / cbdv;
5912af59f7dSMatthias Fuchs 	}
59261974038SBenjamin Herrenschmidt 	opb = plb / opdv;
59361974038SBenjamin Herrenschmidt 	ebc = plb / epdv;
59461974038SBenjamin Herrenschmidt 
59567196d72SJosh Boyer 	if (cpc0_cr0 & 0x80)
59661974038SBenjamin Herrenschmidt 		/* uart0 uses the external clock */
59761974038SBenjamin Herrenschmidt 		uart0 = ser_clk;
59867196d72SJosh Boyer 	else
59961974038SBenjamin Herrenschmidt 		uart0 = cpu / udiv;
60061974038SBenjamin Herrenschmidt 
60167196d72SJosh Boyer 	if (cpc0_cr0 & 0x40)
60261974038SBenjamin Herrenschmidt 		/* uart1 uses the external clock */
60361974038SBenjamin Herrenschmidt 		uart1 = ser_clk;
60467196d72SJosh Boyer 	else
60561974038SBenjamin Herrenschmidt 		uart1 = cpu / udiv;
60661974038SBenjamin Herrenschmidt 
60761974038SBenjamin Herrenschmidt 	/* setup the timebase clock to tick at the cpu frequency */
60861974038SBenjamin Herrenschmidt 	cpc0_cr1 = cpc0_cr1 & ~0x00800000;
60961974038SBenjamin Herrenschmidt 	mtdcr(DCRN_405_CPC0_CR1, cpc0_cr1);
61061974038SBenjamin Herrenschmidt 	tb = cpu;
61161974038SBenjamin Herrenschmidt 
61261974038SBenjamin Herrenschmidt 	dt_fixup_cpu_clocks(cpu, tb, 0);
61361974038SBenjamin Herrenschmidt 	dt_fixup_clock("/plb", plb);
61461974038SBenjamin Herrenschmidt 	dt_fixup_clock("/plb/opb", opb);
61561974038SBenjamin Herrenschmidt 	dt_fixup_clock("/plb/ebc", ebc);
61661974038SBenjamin Herrenschmidt 	dt_fixup_clock("/plb/opb/serial@ef600300", uart0);
61761974038SBenjamin Herrenschmidt 	dt_fixup_clock("/plb/opb/serial@ef600400", uart1);
61861974038SBenjamin Herrenschmidt }
61961974038SBenjamin Herrenschmidt 
6202af59f7dSMatthias Fuchs 
ibm405ep_fixup_clocks(unsigned int sys_clk)6212af59f7dSMatthias Fuchs void ibm405ep_fixup_clocks(unsigned int sys_clk)
6222af59f7dSMatthias Fuchs {
6232af59f7dSMatthias Fuchs 	u32 pllmr0 = mfdcr(DCRN_CPC0_PLLMR0);
6242af59f7dSMatthias Fuchs 	u32 pllmr1 = mfdcr(DCRN_CPC0_PLLMR1);
6252af59f7dSMatthias Fuchs 	u32 cpc0_ucr = mfdcr(DCRN_CPC0_UCR);
6262af59f7dSMatthias Fuchs 	u32 cpu, plb, opb, ebc, uart0, uart1;
6272af59f7dSMatthias Fuchs 	u32 fwdva, fwdvb, fbdv, cbdv, opdv, epdv;
6282af59f7dSMatthias Fuchs 	u32 pllmr0_ccdv, tb, m;
6292af59f7dSMatthias Fuchs 
6302af59f7dSMatthias Fuchs 	fwdva = 8 - ((pllmr1 & 0x00070000) >> 16);
6312af59f7dSMatthias Fuchs 	fwdvb = 8 - ((pllmr1 & 0x00007000) >> 12);
6322af59f7dSMatthias Fuchs 	fbdv = (pllmr1 & 0x00f00000) >> 20;
6332af59f7dSMatthias Fuchs 	if (fbdv == 0)
6342af59f7dSMatthias Fuchs 		fbdv = 16;
6352af59f7dSMatthias Fuchs 
6362af59f7dSMatthias Fuchs 	cbdv = ((pllmr0 & 0x00030000) >> 16) + 1; /* CPU:PLB */
6372af59f7dSMatthias Fuchs 	epdv = ((pllmr0 & 0x00000300) >> 8) + 2;  /* PLB:EBC */
6382af59f7dSMatthias Fuchs 	opdv = ((pllmr0 & 0x00003000) >> 12) + 1; /* PLB:OPB */
6392af59f7dSMatthias Fuchs 
6402af59f7dSMatthias Fuchs 	m = fbdv * fwdvb;
6412af59f7dSMatthias Fuchs 
6422af59f7dSMatthias Fuchs 	pllmr0_ccdv = ((pllmr0 & 0x00300000) >> 20) + 1;
6432af59f7dSMatthias Fuchs 	if (pllmr1 & 0x80000000)
6442af59f7dSMatthias Fuchs 		cpu = sys_clk * m / (fwdva * pllmr0_ccdv);
6452af59f7dSMatthias Fuchs 	else
6462af59f7dSMatthias Fuchs 		cpu = sys_clk / pllmr0_ccdv;
6472af59f7dSMatthias Fuchs 
6482af59f7dSMatthias Fuchs 	plb = cpu / cbdv;
6492af59f7dSMatthias Fuchs 	opb = plb / opdv;
6502af59f7dSMatthias Fuchs 	ebc = plb / epdv;
6512af59f7dSMatthias Fuchs 	tb = cpu;
6522af59f7dSMatthias Fuchs 	uart0 = cpu / (cpc0_ucr & 0x0000007f);
6532af59f7dSMatthias Fuchs 	uart1 = cpu / ((cpc0_ucr & 0x00007f00) >> 8);
6542af59f7dSMatthias Fuchs 
6552af59f7dSMatthias Fuchs 	dt_fixup_cpu_clocks(cpu, tb, 0);
6562af59f7dSMatthias Fuchs 	dt_fixup_clock("/plb", plb);
6572af59f7dSMatthias Fuchs 	dt_fixup_clock("/plb/opb", opb);
6582af59f7dSMatthias Fuchs 	dt_fixup_clock("/plb/ebc", ebc);
6592af59f7dSMatthias Fuchs 	dt_fixup_clock("/plb/opb/serial@ef600300", uart0);
6602af59f7dSMatthias Fuchs 	dt_fixup_clock("/plb/opb/serial@ef600400", uart1);
6612af59f7dSMatthias Fuchs }
6620484c1dfSTiejun Chen 
6630484c1dfSTiejun Chen static u8 ibm405ex_fwdv_multi_bits[] = {
6640484c1dfSTiejun Chen 	/* values for:  1 - 16 */
6650484c1dfSTiejun Chen 	0x01, 0x02, 0x0e, 0x09, 0x04, 0x0b, 0x10, 0x0d, 0x0c, 0x05,
6660484c1dfSTiejun Chen 	0x06, 0x0f, 0x0a, 0x07, 0x08, 0x03
6670484c1dfSTiejun Chen };
6680484c1dfSTiejun Chen 
ibm405ex_get_fwdva(unsigned long cpr_fwdv)6690484c1dfSTiejun Chen u32 ibm405ex_get_fwdva(unsigned long cpr_fwdv)
6700484c1dfSTiejun Chen {
6710484c1dfSTiejun Chen 	u32 index;
6720484c1dfSTiejun Chen 
6730484c1dfSTiejun Chen 	for (index = 0; index < ARRAY_SIZE(ibm405ex_fwdv_multi_bits); index++)
6740484c1dfSTiejun Chen 		if (cpr_fwdv == (u32)ibm405ex_fwdv_multi_bits[index])
6750484c1dfSTiejun Chen 			return index + 1;
6760484c1dfSTiejun Chen 
6770484c1dfSTiejun Chen 	return 0;
6780484c1dfSTiejun Chen }
6790484c1dfSTiejun Chen 
6800484c1dfSTiejun Chen static u8 ibm405ex_fbdv_multi_bits[] = {
6810484c1dfSTiejun Chen 	/* values for:  1 - 100 */
6820484c1dfSTiejun Chen 	0x00, 0xff, 0x7e, 0xfd, 0x7a, 0xf5, 0x6a, 0xd5, 0x2a, 0xd4,
6830484c1dfSTiejun Chen 	0x29, 0xd3, 0x26, 0xcc, 0x19, 0xb3, 0x67, 0xce, 0x1d, 0xbb,
6840484c1dfSTiejun Chen 	0x77, 0xee, 0x5d, 0xba, 0x74, 0xe9, 0x52, 0xa5, 0x4b, 0x96,
6850484c1dfSTiejun Chen 	0x2c, 0xd8, 0x31, 0xe3, 0x46, 0x8d, 0x1b, 0xb7, 0x6f, 0xde,
6860484c1dfSTiejun Chen 	0x3d, 0xfb, 0x76, 0xed, 0x5a, 0xb5, 0x6b, 0xd6, 0x2d, 0xdb,
6870484c1dfSTiejun Chen 	0x36, 0xec, 0x59, 0xb2, 0x64, 0xc9, 0x12, 0xa4, 0x48, 0x91,
6880484c1dfSTiejun Chen 	0x23, 0xc7, 0x0e, 0x9c, 0x38, 0xf0, 0x61, 0xc2, 0x05, 0x8b,
6890484c1dfSTiejun Chen 	0x17, 0xaf, 0x5f, 0xbe, 0x7c, 0xf9, 0x72, 0xe5, 0x4a, 0x95,
6900484c1dfSTiejun Chen 	0x2b, 0xd7, 0x2e, 0xdc, 0x39, 0xf3, 0x66, 0xcd, 0x1a, 0xb4,
6910484c1dfSTiejun Chen 	0x68, 0xd1, 0x22, 0xc4, 0x09, 0x93, 0x27, 0xcf, 0x1e, 0xbc,
6920484c1dfSTiejun Chen 	/* values for:  101 - 200 */
6930484c1dfSTiejun Chen 	0x78, 0xf1, 0x62, 0xc5, 0x0a, 0x94, 0x28, 0xd0, 0x21, 0xc3,
6940484c1dfSTiejun Chen 	0x06, 0x8c, 0x18, 0xb0, 0x60, 0xc1, 0x02, 0x84, 0x08, 0x90,
6950484c1dfSTiejun Chen 	0x20, 0xc0, 0x01, 0x83, 0x07, 0x8f, 0x1f, 0xbf, 0x7f, 0xfe,
6960484c1dfSTiejun Chen 	0x7d, 0xfa, 0x75, 0xea, 0x55, 0xaa, 0x54, 0xa9, 0x53, 0xa6,
6970484c1dfSTiejun Chen 	0x4c, 0x99, 0x33, 0xe7, 0x4e, 0x9d, 0x3b, 0xf7, 0x6e, 0xdd,
6980484c1dfSTiejun Chen 	0x3a, 0xf4, 0x69, 0xd2, 0x25, 0xcb, 0x16, 0xac, 0x58, 0xb1,
6990484c1dfSTiejun Chen 	0x63, 0xc6, 0x0d, 0x9b, 0x37, 0xef, 0x5e, 0xbd, 0x7b, 0xf6,
7000484c1dfSTiejun Chen 	0x6d, 0xda, 0x35, 0xeb, 0x56, 0xad, 0x5b, 0xb6, 0x6c, 0xd9,
7010484c1dfSTiejun Chen 	0x32, 0xe4, 0x49, 0x92, 0x24, 0xc8, 0x11, 0xa3, 0x47, 0x8e,
7020484c1dfSTiejun Chen 	0x1c, 0xb8, 0x70, 0xe1, 0x42, 0x85, 0x0b, 0x97, 0x2f, 0xdf,
7030484c1dfSTiejun Chen 	/* values for:  201 - 255 */
7040484c1dfSTiejun Chen 	0x3e, 0xfc, 0x79, 0xf2, 0x65, 0xca, 0x15, 0xab, 0x57, 0xae,
7050484c1dfSTiejun Chen 	0x5c, 0xb9, 0x73, 0xe6, 0x4d, 0x9a, 0x34, 0xe8, 0x51, 0xa2,
7060484c1dfSTiejun Chen 	0x44, 0x89, 0x13, 0xa7, 0x4f, 0x9e, 0x3c, 0xf8, 0x71, 0xe2,
7070484c1dfSTiejun Chen 	0x45, 0x8a, 0x14, 0xa8, 0x50, 0xa1, 0x43, 0x86, 0x0c, 0x98,
7080484c1dfSTiejun Chen 	0x30, 0xe0, 0x41, 0x82, 0x04, 0x88, 0x10, 0xa0, 0x40, 0x81,
7090484c1dfSTiejun Chen 	0x03, 0x87, 0x0f, 0x9f, 0x3f  /* END */
7100484c1dfSTiejun Chen };
7110484c1dfSTiejun Chen 
ibm405ex_get_fbdv(unsigned long cpr_fbdv)7120484c1dfSTiejun Chen u32 ibm405ex_get_fbdv(unsigned long cpr_fbdv)
7130484c1dfSTiejun Chen {
7140484c1dfSTiejun Chen 	u32 index;
7150484c1dfSTiejun Chen 
7160484c1dfSTiejun Chen 	for (index = 0; index < ARRAY_SIZE(ibm405ex_fbdv_multi_bits); index++)
7170484c1dfSTiejun Chen 		if (cpr_fbdv == (u32)ibm405ex_fbdv_multi_bits[index])
7180484c1dfSTiejun Chen 			return index + 1;
7190484c1dfSTiejun Chen 
7200484c1dfSTiejun Chen 	return 0;
7210484c1dfSTiejun Chen }
7220484c1dfSTiejun Chen 
ibm405ex_fixup_clocks(unsigned int sys_clk,unsigned int uart_clk)7230484c1dfSTiejun Chen void ibm405ex_fixup_clocks(unsigned int sys_clk, unsigned int uart_clk)
7240484c1dfSTiejun Chen {
7250484c1dfSTiejun Chen 	/* PLL config */
7260484c1dfSTiejun Chen 	u32 pllc  = CPR0_READ(DCRN_CPR0_PLLC);
7270484c1dfSTiejun Chen 	u32 plld  = CPR0_READ(DCRN_CPR0_PLLD);
7280484c1dfSTiejun Chen 	u32 cpud  = CPR0_READ(DCRN_CPR0_PRIMAD);
7290484c1dfSTiejun Chen 	u32 plbd  = CPR0_READ(DCRN_CPR0_PRIMBD);
7300484c1dfSTiejun Chen 	u32 opbd  = CPR0_READ(DCRN_CPR0_OPBD);
7310484c1dfSTiejun Chen 	u32 perd  = CPR0_READ(DCRN_CPR0_PERD);
7320484c1dfSTiejun Chen 
7330484c1dfSTiejun Chen 	/* Dividers */
7340484c1dfSTiejun Chen 	u32 fbdv   = ibm405ex_get_fbdv(__fix_zero((plld >> 24) & 0xff, 1));
7350484c1dfSTiejun Chen 
7360484c1dfSTiejun Chen 	u32 fwdva  = ibm405ex_get_fwdva(__fix_zero((plld >> 16) & 0x0f, 1));
7370484c1dfSTiejun Chen 
7380484c1dfSTiejun Chen 	u32 cpudv0 = __fix_zero((cpud >> 24) & 7, 8);
7390484c1dfSTiejun Chen 
7400484c1dfSTiejun Chen 	/* PLBDV0 is hardwared to 010. */
7410484c1dfSTiejun Chen 	u32 plbdv0 = 2;
7420484c1dfSTiejun Chen 	u32 plb2xdv0 = __fix_zero((plbd >> 16) & 7, 8);
7430484c1dfSTiejun Chen 
7440484c1dfSTiejun Chen 	u32 opbdv0 = __fix_zero((opbd >> 24) & 3, 4);
7450484c1dfSTiejun Chen 
7460484c1dfSTiejun Chen 	u32 perdv0 = __fix_zero((perd >> 24) & 3, 4);
7470484c1dfSTiejun Chen 
7480484c1dfSTiejun Chen 	/* Resulting clocks */
7490484c1dfSTiejun Chen 	u32 cpu, plb, opb, ebc, vco, tb, uart0, uart1;
7500484c1dfSTiejun Chen 
7510484c1dfSTiejun Chen 	/* PLL's VCO is the source for primary forward ? */
7520484c1dfSTiejun Chen 	if (pllc & 0x40000000) {
7530484c1dfSTiejun Chen 		u32 m;
7540484c1dfSTiejun Chen 
7550484c1dfSTiejun Chen 		/* Feedback path */
7560484c1dfSTiejun Chen 		switch ((pllc >> 24) & 7) {
7570484c1dfSTiejun Chen 		case 0:
7580484c1dfSTiejun Chen 			/* PLLOUTx */
7590484c1dfSTiejun Chen 			m = fbdv;
7600484c1dfSTiejun Chen 			break;
7610484c1dfSTiejun Chen 		case 1:
7620484c1dfSTiejun Chen 			/* CPU */
7630484c1dfSTiejun Chen 			m = fbdv * fwdva * cpudv0;
7640484c1dfSTiejun Chen 			break;
7650484c1dfSTiejun Chen 		case 5:
7660484c1dfSTiejun Chen 			/* PERClk */
7670484c1dfSTiejun Chen 			m = fbdv * fwdva * plb2xdv0 * plbdv0 * opbdv0 * perdv0;
7680484c1dfSTiejun Chen 			break;
7690484c1dfSTiejun Chen 		default:
7700484c1dfSTiejun Chen 			printf("WARNING ! Invalid PLL feedback source !\n");
7710484c1dfSTiejun Chen 			goto bypass;
7720484c1dfSTiejun Chen 		}
7730484c1dfSTiejun Chen 
7740484c1dfSTiejun Chen 		vco = (unsigned int)(sys_clk * m);
7750484c1dfSTiejun Chen 	} else {
7760484c1dfSTiejun Chen bypass:
7770484c1dfSTiejun Chen 		/* Bypass system PLL */
7780484c1dfSTiejun Chen 		vco = 0;
7790484c1dfSTiejun Chen 	}
7800484c1dfSTiejun Chen 
7810484c1dfSTiejun Chen 	/* CPU = VCO / ( FWDVA x CPUDV0) */
7820484c1dfSTiejun Chen 	cpu = vco / (fwdva * cpudv0);
7830484c1dfSTiejun Chen 	/* PLB = VCO / ( FWDVA x PLB2XDV0 x PLBDV0) */
7840484c1dfSTiejun Chen 	plb = vco / (fwdva * plb2xdv0 * plbdv0);
7850484c1dfSTiejun Chen 	/* OPB = PLB / OPBDV0 */
7860484c1dfSTiejun Chen 	opb = plb / opbdv0;
7870484c1dfSTiejun Chen 	/* EBC = OPB / PERDV0 */
7880484c1dfSTiejun Chen 	ebc = opb / perdv0;
7890484c1dfSTiejun Chen 
7900484c1dfSTiejun Chen 	tb = cpu;
7910484c1dfSTiejun Chen 	uart0 = uart1 = uart_clk;
7920484c1dfSTiejun Chen 
7930484c1dfSTiejun Chen 	dt_fixup_cpu_clocks(cpu, tb, 0);
7940484c1dfSTiejun Chen 	dt_fixup_clock("/plb", plb);
7950484c1dfSTiejun Chen 	dt_fixup_clock("/plb/opb", opb);
7960484c1dfSTiejun Chen 	dt_fixup_clock("/plb/opb/ebc", ebc);
7970484c1dfSTiejun Chen 	dt_fixup_clock("/plb/opb/serial@ef600200", uart0);
7980484c1dfSTiejun Chen 	dt_fixup_clock("/plb/opb/serial@ef600300", uart1);
7990484c1dfSTiejun Chen }
800