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/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); 34#ifdef CONFIG_440EP 35 u32 uart2 = SDR_READ(DCRN_SDR_UART2); 36 u32 uart3 = SDR_READ(DCRN_SDR_UART3); 37#endif 38 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); 100#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 111} 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 122static irqreturn_t l2c_error_handler(int irq, void* dev) 123{ 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 */ 152 if (request_irq(87, l2c_error_handler, IRQF_DISABLED, "L2C", 0) < 0){ 153 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 */ 236 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") 239 == 0 && p->cpu > 667000000)) 240 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 284void __init ibm440gx_platform_init(unsigned long r3, unsigned long r4, 285 unsigned long r5, unsigned long r6, 286 unsigned long r7) 287{ 288 if (!strcmp(cur_cpu_spec->cpu_name, "440GX Rev. C") || 289 !strcmp(cur_cpu_spec->cpu_name, "440GX Rev. F")) 290 mtspr(SPRN_CCR1, mfspr(SPRN_CCR1) | CCR1_DPC); 291 292 ibm44x_platform_init(r3, r4, r5, r6, r7); 293} 294