1 /* 2 * Copyright (C) 2006-2007 PA Semi, Inc 3 * 4 * Authors: Kip Walker, PA Semi 5 * Olof Johansson, PA Semi 6 * 7 * Maintained by: Olof Johansson <olof@lixom.net> 8 * 9 * Based on arch/powerpc/platforms/maple/setup.c 10 * 11 * This program is free software; you can redistribute it and/or modify 12 * it under the terms of the GNU General Public License version 2 as 13 * published by the Free Software Foundation. 14 * 15 * This program is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU General Public License for more details. 19 * 20 * You should have received a copy of the GNU General Public License 21 * along with this program; if not, write to the Free Software 22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 23 */ 24 25 #include <linux/errno.h> 26 #include <linux/kernel.h> 27 #include <linux/delay.h> 28 #include <linux/console.h> 29 #include <linux/pci.h> 30 #include <linux/of_platform.h> 31 32 #include <asm/prom.h> 33 #include <asm/system.h> 34 #include <asm/iommu.h> 35 #include <asm/machdep.h> 36 #include <asm/mpic.h> 37 #include <asm/smp.h> 38 #include <asm/time.h> 39 #include <asm/mmu.h> 40 41 #include <pcmcia/ss.h> 42 #include <pcmcia/cistpl.h> 43 #include <pcmcia/ds.h> 44 45 #include "pasemi.h" 46 47 /* SDC reset register, must be pre-mapped at reset time */ 48 static void __iomem *reset_reg; 49 50 /* Various error status registers, must be pre-mapped at MCE time */ 51 52 #define MAX_MCE_REGS 32 53 struct mce_regs { 54 char *name; 55 void __iomem *addr; 56 }; 57 58 static struct mce_regs mce_regs[MAX_MCE_REGS]; 59 static int num_mce_regs; 60 static int nmi_virq = NO_IRQ; 61 62 63 static void pas_restart(char *cmd) 64 { 65 /* Need to put others cpu in hold loop so they're not sleeping */ 66 smp_send_stop(); 67 udelay(10000); 68 printk("Restarting...\n"); 69 while (1) 70 out_le32(reset_reg, 0x6000000); 71 } 72 73 #ifdef CONFIG_SMP 74 static DEFINE_SPINLOCK(timebase_lock); 75 static unsigned long timebase; 76 77 static void __devinit pas_give_timebase(void) 78 { 79 spin_lock(&timebase_lock); 80 mtspr(SPRN_TBCTL, TBCTL_FREEZE); 81 isync(); 82 timebase = get_tb(); 83 spin_unlock(&timebase_lock); 84 85 while (timebase) 86 barrier(); 87 mtspr(SPRN_TBCTL, TBCTL_RESTART); 88 } 89 90 static void __devinit pas_take_timebase(void) 91 { 92 while (!timebase) 93 smp_rmb(); 94 95 spin_lock(&timebase_lock); 96 set_tb(timebase >> 32, timebase & 0xffffffff); 97 timebase = 0; 98 spin_unlock(&timebase_lock); 99 } 100 101 struct smp_ops_t pas_smp_ops = { 102 .probe = smp_mpic_probe, 103 .message_pass = smp_mpic_message_pass, 104 .kick_cpu = smp_generic_kick_cpu, 105 .setup_cpu = smp_mpic_setup_cpu, 106 .give_timebase = pas_give_timebase, 107 .take_timebase = pas_take_timebase, 108 }; 109 #endif /* CONFIG_SMP */ 110 111 void __init pas_setup_arch(void) 112 { 113 #ifdef CONFIG_SMP 114 /* Setup SMP callback */ 115 smp_ops = &pas_smp_ops; 116 #endif 117 /* Lookup PCI hosts */ 118 pas_pci_init(); 119 120 #ifdef CONFIG_DUMMY_CONSOLE 121 conswitchp = &dummy_con; 122 #endif 123 124 /* Remap SDC register for doing reset */ 125 /* XXXOJN This should maybe come out of the device tree */ 126 reset_reg = ioremap(0xfc101100, 4); 127 } 128 129 static int __init pas_setup_mce_regs(void) 130 { 131 struct pci_dev *dev; 132 int reg; 133 134 /* Remap various SoC status registers for use by the MCE handler */ 135 136 reg = 0; 137 138 dev = pci_get_device(PCI_VENDOR_ID_PASEMI, 0xa00a, NULL); 139 while (dev && reg < MAX_MCE_REGS) { 140 mce_regs[reg].name = kasprintf(GFP_KERNEL, 141 "mc%d_mcdebug_errsta", reg); 142 mce_regs[reg].addr = pasemi_pci_getcfgaddr(dev, 0x730); 143 dev = pci_get_device(PCI_VENDOR_ID_PASEMI, 0xa00a, dev); 144 reg++; 145 } 146 147 dev = pci_get_device(PCI_VENDOR_ID_PASEMI, 0xa001, NULL); 148 if (dev && reg+4 < MAX_MCE_REGS) { 149 mce_regs[reg].name = "iobdbg_IntStatus1"; 150 mce_regs[reg].addr = pasemi_pci_getcfgaddr(dev, 0x438); 151 reg++; 152 mce_regs[reg].name = "iobdbg_IOCTbusIntDbgReg"; 153 mce_regs[reg].addr = pasemi_pci_getcfgaddr(dev, 0x454); 154 reg++; 155 mce_regs[reg].name = "iobiom_IntStatus"; 156 mce_regs[reg].addr = pasemi_pci_getcfgaddr(dev, 0xc10); 157 reg++; 158 mce_regs[reg].name = "iobiom_IntDbgReg"; 159 mce_regs[reg].addr = pasemi_pci_getcfgaddr(dev, 0xc1c); 160 reg++; 161 } 162 163 dev = pci_get_device(PCI_VENDOR_ID_PASEMI, 0xa009, NULL); 164 if (dev && reg+2 < MAX_MCE_REGS) { 165 mce_regs[reg].name = "l2csts_IntStatus"; 166 mce_regs[reg].addr = pasemi_pci_getcfgaddr(dev, 0x200); 167 reg++; 168 mce_regs[reg].name = "l2csts_Cnt"; 169 mce_regs[reg].addr = pasemi_pci_getcfgaddr(dev, 0x214); 170 reg++; 171 } 172 173 num_mce_regs = reg; 174 175 return 0; 176 } 177 machine_device_initcall(pasemi, pas_setup_mce_regs); 178 179 static __init void pas_init_IRQ(void) 180 { 181 struct device_node *np; 182 struct device_node *root, *mpic_node; 183 unsigned long openpic_addr; 184 const unsigned int *opprop; 185 int naddr, opplen; 186 int mpic_flags; 187 const unsigned int *nmiprop; 188 struct mpic *mpic; 189 190 mpic_node = NULL; 191 192 for_each_node_by_type(np, "interrupt-controller") 193 if (of_device_is_compatible(np, "open-pic")) { 194 mpic_node = np; 195 break; 196 } 197 if (!mpic_node) 198 for_each_node_by_type(np, "open-pic") { 199 mpic_node = np; 200 break; 201 } 202 if (!mpic_node) { 203 printk(KERN_ERR 204 "Failed to locate the MPIC interrupt controller\n"); 205 return; 206 } 207 208 /* Find address list in /platform-open-pic */ 209 root = of_find_node_by_path("/"); 210 naddr = of_n_addr_cells(root); 211 opprop = of_get_property(root, "platform-open-pic", &opplen); 212 if (!opprop) { 213 printk(KERN_ERR "No platform-open-pic property.\n"); 214 of_node_put(root); 215 return; 216 } 217 openpic_addr = of_read_number(opprop, naddr); 218 printk(KERN_DEBUG "OpenPIC addr: %lx\n", openpic_addr); 219 220 mpic_flags = MPIC_PRIMARY | MPIC_LARGE_VECTORS | MPIC_NO_BIAS; 221 222 nmiprop = of_get_property(mpic_node, "nmi-source", NULL); 223 if (nmiprop) 224 mpic_flags |= MPIC_ENABLE_MCK; 225 226 mpic = mpic_alloc(mpic_node, openpic_addr, 227 mpic_flags, 0, 0, "PASEMI-OPIC"); 228 BUG_ON(!mpic); 229 230 mpic_assign_isu(mpic, 0, openpic_addr + 0x10000); 231 mpic_init(mpic); 232 /* The NMI/MCK source needs to be prio 15 */ 233 if (nmiprop) { 234 nmi_virq = irq_create_mapping(NULL, *nmiprop); 235 mpic_irq_set_priority(nmi_virq, 15); 236 set_irq_type(nmi_virq, IRQ_TYPE_EDGE_RISING); 237 mpic_unmask_irq(nmi_virq); 238 } 239 240 of_node_put(mpic_node); 241 of_node_put(root); 242 } 243 244 static void __init pas_progress(char *s, unsigned short hex) 245 { 246 printk("[%04x] : %s\n", hex, s ? s : ""); 247 } 248 249 250 static int pas_machine_check_handler(struct pt_regs *regs) 251 { 252 int cpu = smp_processor_id(); 253 unsigned long srr0, srr1, dsisr; 254 int dump_slb = 0; 255 int i; 256 257 srr0 = regs->nip; 258 srr1 = regs->msr; 259 260 if (nmi_virq != NO_IRQ && mpic_get_mcirq() == nmi_virq) { 261 printk(KERN_ERR "NMI delivered\n"); 262 debugger(regs); 263 mpic_end_irq(nmi_virq); 264 goto out; 265 } 266 267 dsisr = mfspr(SPRN_DSISR); 268 printk(KERN_ERR "Machine Check on CPU %d\n", cpu); 269 printk(KERN_ERR "SRR0 0x%016lx SRR1 0x%016lx\n", srr0, srr1); 270 printk(KERN_ERR "DSISR 0x%016lx DAR 0x%016lx\n", dsisr, regs->dar); 271 printk(KERN_ERR "BER 0x%016lx MER 0x%016lx\n", mfspr(SPRN_PA6T_BER), 272 mfspr(SPRN_PA6T_MER)); 273 printk(KERN_ERR "IER 0x%016lx DER 0x%016lx\n", mfspr(SPRN_PA6T_IER), 274 mfspr(SPRN_PA6T_DER)); 275 printk(KERN_ERR "Cause:\n"); 276 277 if (srr1 & 0x200000) 278 printk(KERN_ERR "Signalled by SDC\n"); 279 280 if (srr1 & 0x100000) { 281 printk(KERN_ERR "Load/Store detected error:\n"); 282 if (dsisr & 0x8000) 283 printk(KERN_ERR "D-cache ECC double-bit error or bus error\n"); 284 if (dsisr & 0x4000) 285 printk(KERN_ERR "LSU snoop response error\n"); 286 if (dsisr & 0x2000) { 287 printk(KERN_ERR "MMU SLB multi-hit or invalid B field\n"); 288 dump_slb = 1; 289 } 290 if (dsisr & 0x1000) 291 printk(KERN_ERR "Recoverable Duptags\n"); 292 if (dsisr & 0x800) 293 printk(KERN_ERR "Recoverable D-cache parity error count overflow\n"); 294 if (dsisr & 0x400) 295 printk(KERN_ERR "TLB parity error count overflow\n"); 296 } 297 298 if (srr1 & 0x80000) 299 printk(KERN_ERR "Bus Error\n"); 300 301 if (srr1 & 0x40000) { 302 printk(KERN_ERR "I-side SLB multiple hit\n"); 303 dump_slb = 1; 304 } 305 306 if (srr1 & 0x20000) 307 printk(KERN_ERR "I-cache parity error hit\n"); 308 309 if (num_mce_regs == 0) 310 printk(KERN_ERR "No MCE registers mapped yet, can't dump\n"); 311 else 312 printk(KERN_ERR "SoC debug registers:\n"); 313 314 for (i = 0; i < num_mce_regs; i++) 315 printk(KERN_ERR "%s: 0x%08x\n", mce_regs[i].name, 316 in_le32(mce_regs[i].addr)); 317 318 if (dump_slb) { 319 unsigned long e, v; 320 int i; 321 322 printk(KERN_ERR "slb contents:\n"); 323 for (i = 0; i < mmu_slb_size; i++) { 324 asm volatile("slbmfee %0,%1" : "=r" (e) : "r" (i)); 325 asm volatile("slbmfev %0,%1" : "=r" (v) : "r" (i)); 326 printk(KERN_ERR "%02d %016lx %016lx\n", i, e, v); 327 } 328 } 329 330 out: 331 /* SRR1[62] is from MSR[62] if recoverable, so pass that back */ 332 return !!(srr1 & 0x2); 333 } 334 335 static void __init pas_init_early(void) 336 { 337 iommu_init_early_pasemi(); 338 } 339 340 #ifdef CONFIG_PCMCIA 341 static int pcmcia_notify(struct notifier_block *nb, unsigned long action, 342 void *data) 343 { 344 struct device *dev = data; 345 struct device *parent; 346 struct pcmcia_device *pdev = to_pcmcia_dev(dev); 347 348 /* We are only intereted in device addition */ 349 if (action != BUS_NOTIFY_ADD_DEVICE) 350 return 0; 351 352 parent = pdev->socket->dev.parent; 353 354 /* We know electra_cf devices will always have of_node set, since 355 * electra_cf is an of_platform driver. 356 */ 357 if (!parent->archdata.of_node) 358 return 0; 359 360 if (!of_device_is_compatible(parent->archdata.of_node, "electra-cf")) 361 return 0; 362 363 /* We use the direct ops for localbus */ 364 dev->archdata.dma_ops = &dma_direct_ops; 365 366 return 0; 367 } 368 369 static struct notifier_block pcmcia_notifier = { 370 .notifier_call = pcmcia_notify, 371 }; 372 373 static inline void pasemi_pcmcia_init(void) 374 { 375 extern struct bus_type pcmcia_bus_type; 376 377 bus_register_notifier(&pcmcia_bus_type, &pcmcia_notifier); 378 } 379 380 #else 381 382 static inline void pasemi_pcmcia_init(void) 383 { 384 } 385 386 #endif 387 388 389 static struct of_device_id pasemi_bus_ids[] = { 390 /* Unfortunately needed for legacy firmwares */ 391 { .type = "localbus", }, 392 { .type = "sdc", }, 393 /* These are the proper entries, which newer firmware uses */ 394 { .compatible = "pasemi,localbus", }, 395 { .compatible = "pasemi,sdc", }, 396 {}, 397 }; 398 399 static int __init pasemi_publish_devices(void) 400 { 401 pasemi_pcmcia_init(); 402 403 /* Publish OF platform devices for SDC and other non-PCI devices */ 404 of_platform_bus_probe(NULL, pasemi_bus_ids, NULL); 405 406 return 0; 407 } 408 machine_device_initcall(pasemi, pasemi_publish_devices); 409 410 411 /* 412 * Called very early, MMU is off, device-tree isn't unflattened 413 */ 414 static int __init pas_probe(void) 415 { 416 unsigned long root = of_get_flat_dt_root(); 417 418 if (!of_flat_dt_is_compatible(root, "PA6T-1682M") && 419 !of_flat_dt_is_compatible(root, "pasemi,pwrficient")) 420 return 0; 421 422 hpte_init_native(); 423 424 alloc_iobmap_l2(); 425 426 return 1; 427 } 428 429 define_machine(pasemi) { 430 .name = "PA Semi PWRficient", 431 .probe = pas_probe, 432 .setup_arch = pas_setup_arch, 433 .init_early = pas_init_early, 434 .init_IRQ = pas_init_IRQ, 435 .get_irq = mpic_get_irq, 436 .restart = pas_restart, 437 .get_boot_time = pas_get_boot_time, 438 .calibrate_decr = generic_calibrate_decr, 439 .progress = pas_progress, 440 .machine_check_exception = pas_machine_check_handler, 441 }; 442