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