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