blob: 6ad52f4a26e171dd4c586459375b71a08f0ad439 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002 * PPC440GX system library
3 *
4 * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
Eugene Surovegin30aaceb2006-04-25 01:22:44 -07005 * Copyright (c) 2003 - 2006 Zultys Technologies
Linus Torvalds1da177e2005-04-16 15:20:36 -07006 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version.
11 *
12 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070013#include <linux/kernel.h>
14#include <linux/interrupt.h>
15#include <asm/ibm44x.h>
16#include <asm/mmu.h>
17#include <asm/processor.h>
18#include <syslib/ibm440gx_common.h>
19
20/*
21 * Calculate 440GX clocks
22 */
23static inline u32 __fix_zero(u32 v, u32 def){
24 return v ? v : def;
25}
26
27void __init ibm440gx_get_clocks(struct ibm44x_clocks* p, unsigned int sys_clk,
28 unsigned int ser_clk)
29{
30 u32 pllc = CPR_READ(DCRN_CPR_PLLC);
31 u32 plld = CPR_READ(DCRN_CPR_PLLD);
32 u32 uart0 = SDR_READ(DCRN_SDR_UART0);
33 u32 uart1 = SDR_READ(DCRN_SDR_UART1);
Matt Porterc9cf73a2005-07-31 22:34:52 -070034#ifdef CONFIG_440EP
35 u32 uart2 = SDR_READ(DCRN_SDR_UART2);
36 u32 uart3 = SDR_READ(DCRN_SDR_UART3);
37#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070038
39 /* Dividers */
40 u32 fbdv = __fix_zero((plld >> 24) & 0x1f, 32);
41 u32 fwdva = __fix_zero((plld >> 16) & 0xf, 16);
42 u32 fwdvb = __fix_zero((plld >> 8) & 7, 8);
43 u32 lfbdv = __fix_zero(plld & 0x3f, 64);
44 u32 pradv0 = __fix_zero((CPR_READ(DCRN_CPR_PRIMAD) >> 24) & 7, 8);
45 u32 prbdv0 = __fix_zero((CPR_READ(DCRN_CPR_PRIMBD) >> 24) & 7, 8);
46 u32 opbdv0 = __fix_zero((CPR_READ(DCRN_CPR_OPBD) >> 24) & 3, 4);
47 u32 perdv0 = __fix_zero((CPR_READ(DCRN_CPR_PERD) >> 24) & 3, 4);
48
49 /* Input clocks for primary dividers */
50 u32 clk_a, clk_b;
51
52 if (pllc & 0x40000000){
53 u32 m;
54
55 /* Feedback path */
56 switch ((pllc >> 24) & 7){
57 case 0:
58 /* PLLOUTx */
59 m = ((pllc & 0x20000000) ? fwdvb : fwdva) * lfbdv;
60 break;
61 case 1:
62 /* CPU */
63 m = fwdva * pradv0;
64 break;
65 case 5:
66 /* PERClk */
67 m = fwdvb * prbdv0 * opbdv0 * perdv0;
68 break;
69 default:
70 printk(KERN_EMERG "invalid PLL feedback source\n");
71 goto bypass;
72 }
73 m *= fbdv;
74 p->vco = sys_clk * m;
75 clk_a = p->vco / fwdva;
76 clk_b = p->vco / fwdvb;
77 }
78 else {
79bypass:
80 /* Bypass system PLL */
81 p->vco = 0;
82 clk_a = clk_b = sys_clk;
83 }
84
85 p->cpu = clk_a / pradv0;
86 p->plb = clk_b / prbdv0;
87 p->opb = p->plb / opbdv0;
88 p->ebc = p->opb / perdv0;
89
90 /* UARTs clock */
91 if (uart0 & 0x00800000)
92 p->uart0 = ser_clk;
93 else
94 p->uart0 = p->plb / __fix_zero(uart0 & 0xff, 256);
95
96 if (uart1 & 0x00800000)
97 p->uart1 = ser_clk;
98 else
99 p->uart1 = p->plb / __fix_zero(uart1 & 0xff, 256);
Matt Porterc9cf73a2005-07-31 22:34:52 -0700100#ifdef CONFIG_440EP
101 if (uart2 & 0x00800000)
102 p->uart2 = ser_clk;
103 else
104 p->uart2 = p->plb / __fix_zero(uart2 & 0xff, 256);
105
106 if (uart3 & 0x00800000)
107 p->uart3 = ser_clk;
108 else
109 p->uart3 = p->plb / __fix_zero(uart3 & 0xff, 256);
110#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111}
112
113/* Issue L2C diagnostic command */
114static inline u32 l2c_diag(u32 addr)
115{
116 mtdcr(DCRN_L2C0_ADDR, addr);
117 mtdcr(DCRN_L2C0_CMD, L2C_CMD_DIAG);
118 while (!(mfdcr(DCRN_L2C0_SR) & L2C_SR_CC)) ;
119 return mfdcr(DCRN_L2C0_DATA);
120}
121
Al Viro39e3eb72006-10-09 12:48:42 +0100122static irqreturn_t l2c_error_handler(int irq, void* dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123{
124 u32 sr = mfdcr(DCRN_L2C0_SR);
125 if (sr & L2C_SR_CPE){
126 /* Read cache trapped address */
127 u32 addr = l2c_diag(0x42000000);
128 printk(KERN_EMERG "L2C: Cache Parity Error, addr[16:26] = 0x%08x\n", addr);
129 }
130 if (sr & L2C_SR_TPE){
131 /* Read tag trapped address */
132 u32 addr = l2c_diag(0x82000000) >> 16;
133 printk(KERN_EMERG "L2C: Tag Parity Error, addr[16:26] = 0x%08x\n", addr);
134 }
135
136 /* Clear parity errors */
137 if (sr & (L2C_SR_CPE | L2C_SR_TPE)){
138 mtdcr(DCRN_L2C0_ADDR, 0);
139 mtdcr(DCRN_L2C0_CMD, L2C_CMD_CCP | L2C_CMD_CTE);
140 } else
141 printk(KERN_EMERG "L2C: LRU error\n");
142
143 return IRQ_HANDLED;
144}
145
146/* Enable L2 cache */
147void __init ibm440gx_l2c_enable(void){
148 u32 r;
149 unsigned long flags;
150
151 /* Install error handler */
Thomas Gleixnerbc59d282006-07-01 19:29:22 -0700152 if (request_irq(87, l2c_error_handler, IRQF_DISABLED, "L2C", 0) < 0){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153 printk(KERN_ERR "Cannot install L2C error handler, cache is not enabled\n");
154 return;
155 }
156
157 local_irq_save(flags);
158 asm volatile ("sync" ::: "memory");
159
160 /* Disable SRAM */
161 mtdcr(DCRN_SRAM0_DPC, mfdcr(DCRN_SRAM0_DPC) & ~SRAM_DPC_ENABLE);
162 mtdcr(DCRN_SRAM0_SB0CR, mfdcr(DCRN_SRAM0_SB0CR) & ~SRAM_SBCR_BU_MASK);
163 mtdcr(DCRN_SRAM0_SB1CR, mfdcr(DCRN_SRAM0_SB1CR) & ~SRAM_SBCR_BU_MASK);
164 mtdcr(DCRN_SRAM0_SB2CR, mfdcr(DCRN_SRAM0_SB2CR) & ~SRAM_SBCR_BU_MASK);
165 mtdcr(DCRN_SRAM0_SB3CR, mfdcr(DCRN_SRAM0_SB3CR) & ~SRAM_SBCR_BU_MASK);
166
167 /* Enable L2_MODE without ICU/DCU */
168 r = mfdcr(DCRN_L2C0_CFG) & ~(L2C_CFG_ICU | L2C_CFG_DCU | L2C_CFG_SS_MASK);
169 r |= L2C_CFG_L2M | L2C_CFG_SS_256;
170 mtdcr(DCRN_L2C0_CFG, r);
171
172 mtdcr(DCRN_L2C0_ADDR, 0);
173
174 /* Hardware Clear Command */
175 mtdcr(DCRN_L2C0_CMD, L2C_CMD_HCC);
176 while (!(mfdcr(DCRN_L2C0_SR) & L2C_SR_CC)) ;
177
178 /* Clear Cache Parity and Tag Errors */
179 mtdcr(DCRN_L2C0_CMD, L2C_CMD_CCP | L2C_CMD_CTE);
180
181 /* Enable 64G snoop region starting at 0 */
182 r = mfdcr(DCRN_L2C0_SNP0) & ~(L2C_SNP_BA_MASK | L2C_SNP_SSR_MASK);
183 r |= L2C_SNP_SSR_32G | L2C_SNP_ESR;
184 mtdcr(DCRN_L2C0_SNP0, r);
185
186 r = mfdcr(DCRN_L2C0_SNP1) & ~(L2C_SNP_BA_MASK | L2C_SNP_SSR_MASK);
187 r |= 0x80000000 | L2C_SNP_SSR_32G | L2C_SNP_ESR;
188 mtdcr(DCRN_L2C0_SNP1, r);
189
190 asm volatile ("sync" ::: "memory");
191
192 /* Enable ICU/DCU ports */
193 r = mfdcr(DCRN_L2C0_CFG);
194 r &= ~(L2C_CFG_DCW_MASK | L2C_CFG_PMUX_MASK | L2C_CFG_PMIM | L2C_CFG_TPEI
195 | L2C_CFG_CPEI | L2C_CFG_NAM | L2C_CFG_NBRM);
196 r |= L2C_CFG_ICU | L2C_CFG_DCU | L2C_CFG_TPC | L2C_CFG_CPC | L2C_CFG_FRAN
197 | L2C_CFG_CPIM | L2C_CFG_TPIM | L2C_CFG_LIM | L2C_CFG_SMCM;
198 mtdcr(DCRN_L2C0_CFG, r);
199
200 asm volatile ("sync; isync" ::: "memory");
201 local_irq_restore(flags);
202}
203
204/* Disable L2 cache */
205void __init ibm440gx_l2c_disable(void){
206 u32 r;
207 unsigned long flags;
208
209 local_irq_save(flags);
210 asm volatile ("sync" ::: "memory");
211
212 /* Disable L2C mode */
213 r = mfdcr(DCRN_L2C0_CFG) & ~(L2C_CFG_L2M | L2C_CFG_ICU | L2C_CFG_DCU);
214 mtdcr(DCRN_L2C0_CFG, r);
215
216 /* Enable SRAM */
217 mtdcr(DCRN_SRAM0_DPC, mfdcr(DCRN_SRAM0_DPC) | SRAM_DPC_ENABLE);
218 mtdcr(DCRN_SRAM0_SB0CR,
219 SRAM_SBCR_BAS0 | SRAM_SBCR_BS_64KB | SRAM_SBCR_BU_RW);
220 mtdcr(DCRN_SRAM0_SB1CR,
221 SRAM_SBCR_BAS1 | SRAM_SBCR_BS_64KB | SRAM_SBCR_BU_RW);
222 mtdcr(DCRN_SRAM0_SB2CR,
223 SRAM_SBCR_BAS2 | SRAM_SBCR_BS_64KB | SRAM_SBCR_BU_RW);
224 mtdcr(DCRN_SRAM0_SB3CR,
225 SRAM_SBCR_BAS3 | SRAM_SBCR_BS_64KB | SRAM_SBCR_BU_RW);
226
227 asm volatile ("sync; isync" ::: "memory");
228 local_irq_restore(flags);
229}
230
231void __init ibm440gx_l2c_setup(struct ibm44x_clocks* p)
232{
233 /* Disable L2C on rev.A, rev.B and 800MHz version of rev.C,
234 enable it on all other revisions
235 */
Kumar Gala400d2212005-09-27 15:13:12 -0500236 if (strcmp(cur_cpu_spec->cpu_name, "440GX Rev. A") == 0 ||
237 strcmp(cur_cpu_spec->cpu_name, "440GX Rev. B") == 0
238 || (strcmp(cur_cpu_spec->cpu_name, "440GX Rev. C")
Tom Rini95409aa2005-09-09 13:01:48 -0700239 == 0 && p->cpu > 667000000))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240 ibm440gx_l2c_disable();
241 else
242 ibm440gx_l2c_enable();
243}
244
245int __init ibm440gx_get_eth_grp(void)
246{
247 return (SDR_READ(DCRN_SDR_PFC1) & DCRN_SDR_PFC1_EPS) >> DCRN_SDR_PFC1_EPS_SHIFT;
248}
249
250void __init ibm440gx_set_eth_grp(int group)
251{
252 SDR_WRITE(DCRN_SDR_PFC1, (SDR_READ(DCRN_SDR_PFC1) & ~DCRN_SDR_PFC1_EPS) | (group << DCRN_SDR_PFC1_EPS_SHIFT));
253}
254
255void __init ibm440gx_tah_enable(void)
256{
257 /* Enable TAH0 and TAH1 */
258 SDR_WRITE(DCRN_SDR_MFR,SDR_READ(DCRN_SDR_MFR) &
259 ~DCRN_SDR_MFR_TAH0);
260 SDR_WRITE(DCRN_SDR_MFR,SDR_READ(DCRN_SDR_MFR) &
261 ~DCRN_SDR_MFR_TAH1);
262}
263
264int ibm440gx_show_cpuinfo(struct seq_file *m){
265
266 u32 l2c_cfg = mfdcr(DCRN_L2C0_CFG);
267 const char* s;
268 if (l2c_cfg & L2C_CFG_L2M){
269 switch (l2c_cfg & (L2C_CFG_ICU | L2C_CFG_DCU)){
270 case L2C_CFG_ICU: s = "I-Cache only"; break;
271 case L2C_CFG_DCU: s = "D-Cache only"; break;
272 default: s = "I-Cache/D-Cache"; break;
273 }
274 }
275 else
276 s = "disabled";
277
278 seq_printf(m, "L2-Cache\t: %s (0x%08x 0x%08x)\n", s,
279 l2c_cfg, mfdcr(DCRN_L2C0_SR));
280
281 return 0;
282}
283
Eugene Surovegin30aaceb2006-04-25 01:22:44 -0700284void __init ibm440gx_platform_init(unsigned long r3, unsigned long r4,
285 unsigned long r5, unsigned long r6,
286 unsigned long r7)
287{
288 /* Erratum 440_43 workaround, disable L1 cache parity checking */
289 if (!strcmp(cur_cpu_spec->cpu_name, "440GX Rev. C") ||
290 !strcmp(cur_cpu_spec->cpu_name, "440GX Rev. F"))
291 mtspr(SPRN_CCR1, mfspr(SPRN_CCR1) | CCR1_DPC);
292
293 ibm44x_platform_init(r3, r4, r5, r6, r7);
294}