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