Commit | Line | Data |
---|---|---|
f6dfc805 DG |
1 | /* |
2 | * Copyright 2007 David Gibson, IBM Corporation. | |
3 | * | |
4 | * Based on earlier code: | |
5 | * Copyright (C) Paul Mackerras 1997. | |
6 | * | |
7 | * Matt Porter <mporter@kernel.crashing.org> | |
8 | * Copyright 2002-2005 MontaVista Software Inc. | |
9 | * | |
10 | * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net> | |
11 | * Copyright (c) 2003, 2004 Zultys Technologies | |
12 | * | |
13 | * This program is free software; you can redistribute it and/or | |
14 | * modify it under the terms of the GNU General Public License | |
15 | * as published by the Free Software Foundation; either version | |
16 | * 2 of the License, or (at your option) any later version. | |
17 | */ | |
18 | #include <stdarg.h> | |
19 | #include <stddef.h> | |
20 | #include "types.h" | |
21 | #include "elf.h" | |
22 | #include "string.h" | |
23 | #include "stdio.h" | |
24 | #include "page.h" | |
25 | #include "ops.h" | |
26 | #include "reg.h" | |
27 | #include "dcr.h" | |
28 | #include "44x.h" | |
29 | ||
30 | extern char _dtb_start[]; | |
31 | extern char _dtb_end[]; | |
32 | ||
33 | static u8 *ebony_mac0, *ebony_mac1; | |
34 | ||
35 | /* Calculate 440GP clocks */ | |
36 | void ibm440gp_fixup_clocks(unsigned int sysclk, unsigned int ser_clk) | |
37 | { | |
38 | u32 sys0 = mfdcr(DCRN_CPC0_SYS0); | |
39 | u32 cr0 = mfdcr(DCRN_CPC0_CR0); | |
40 | u32 cpu, plb, opb, ebc, tb, uart0, uart1, m; | |
41 | u32 opdv = CPC0_SYS0_OPDV(sys0); | |
42 | u32 epdv = CPC0_SYS0_EPDV(sys0); | |
43 | ||
44 | if (sys0 & CPC0_SYS0_BYPASS) { | |
45 | /* Bypass system PLL */ | |
46 | cpu = plb = sysclk; | |
47 | } else { | |
48 | if (sys0 & CPC0_SYS0_EXTSL) | |
49 | /* PerClk */ | |
50 | m = CPC0_SYS0_FWDVB(sys0) * opdv * epdv; | |
51 | else | |
52 | /* CPU clock */ | |
53 | m = CPC0_SYS0_FBDV(sys0) * CPC0_SYS0_FWDVA(sys0); | |
54 | cpu = sysclk * m / CPC0_SYS0_FWDVA(sys0); | |
55 | plb = sysclk * m / CPC0_SYS0_FWDVB(sys0); | |
56 | } | |
57 | ||
58 | opb = plb / opdv; | |
59 | ebc = opb / epdv; | |
60 | ||
61 | /* FIXME: Check if this is for all 440GP, or just Ebony */ | |
62 | if ((mfpvr() & 0xf0000fff) == 0x40000440) | |
63 | /* Rev. B 440GP, use external system clock */ | |
64 | tb = sysclk; | |
65 | else | |
66 | /* Rev. C 440GP, errata force us to use internal clock */ | |
67 | tb = cpu; | |
68 | ||
69 | if (cr0 & CPC0_CR0_U0EC) | |
70 | /* External UART clock */ | |
71 | uart0 = ser_clk; | |
72 | else | |
73 | /* Internal UART clock */ | |
74 | uart0 = plb / CPC0_CR0_UDIV(cr0); | |
75 | ||
76 | if (cr0 & CPC0_CR0_U1EC) | |
77 | /* External UART clock */ | |
78 | uart1 = ser_clk; | |
79 | else | |
80 | /* Internal UART clock */ | |
81 | uart1 = plb / CPC0_CR0_UDIV(cr0); | |
82 | ||
83 | printf("PPC440GP: SysClk = %dMHz (%x)\n\r", | |
84 | (sysclk + 500000) / 1000000, sysclk); | |
85 | ||
86 | dt_fixup_cpu_clocks(cpu, tb, 0); | |
87 | ||
88 | dt_fixup_clock("/plb", plb); | |
89 | dt_fixup_clock("/plb/opb", opb); | |
90 | dt_fixup_clock("/plb/opb/ebc", ebc); | |
91 | dt_fixup_clock("/plb/opb/serial@40000200", uart0); | |
92 | dt_fixup_clock("/plb/opb/serial@40000300", uart1); | |
93 | } | |
94 | ||
95 | static void ebony_fixups(void) | |
96 | { | |
97 | // FIXME: sysclk should be derived by reading the FPGA registers | |
98 | unsigned long sysclk = 33000000; | |
99 | ||
100 | ibm440gp_fixup_clocks(sysclk, 6 * 1843200); | |
101 | ibm44x_fixup_memsize(); | |
102 | dt_fixup_mac_addresses(ebony_mac0, ebony_mac1); | |
103 | } | |
104 | ||
105 | #define SPRN_DBCR0 0x134 | |
106 | #define DBCR0_RST_SYSTEM 0x30000000 | |
107 | ||
108 | static void ebony_exit(void) | |
109 | { | |
110 | unsigned long tmp; | |
111 | ||
112 | asm volatile ( | |
113 | "mfspr %0,%1\n" | |
114 | "oris %0,%0,%2@h\n" | |
115 | "mtspr %1,%0" | |
116 | : "=&r"(tmp) : "i"(SPRN_DBCR0), "i"(DBCR0_RST_SYSTEM) | |
117 | ); | |
118 | ||
119 | } | |
120 | ||
121 | void ebony_init(void *mac0, void *mac1) | |
122 | { | |
123 | platform_ops.fixups = ebony_fixups; | |
124 | platform_ops.exit = ebony_exit; | |
125 | ebony_mac0 = mac0; | |
126 | ebony_mac1 = mac1; | |
127 | ft_init(_dtb_start, _dtb_end - _dtb_start, 32); | |
128 | serial_console_init(); | |
129 | } |