162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2006-2007 PA Semi, Inc 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Authors: Kip Walker, PA Semi 662306a36Sopenharmony_ci * Olof Johansson, PA Semi 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * Maintained by: Olof Johansson <olof@lixom.net> 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * Based on arch/powerpc/platforms/maple/setup.c 1162306a36Sopenharmony_ci */ 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include <linux/errno.h> 1462306a36Sopenharmony_ci#include <linux/kernel.h> 1562306a36Sopenharmony_ci#include <linux/delay.h> 1662306a36Sopenharmony_ci#include <linux/console.h> 1762306a36Sopenharmony_ci#include <linux/export.h> 1862306a36Sopenharmony_ci#include <linux/pci.h> 1962306a36Sopenharmony_ci#include <linux/of.h> 2062306a36Sopenharmony_ci#include <linux/of_platform.h> 2162306a36Sopenharmony_ci#include <linux/platform_device.h> 2262306a36Sopenharmony_ci#include <linux/gfp.h> 2362306a36Sopenharmony_ci#include <linux/irqdomain.h> 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci#include <asm/iommu.h> 2662306a36Sopenharmony_ci#include <asm/machdep.h> 2762306a36Sopenharmony_ci#include <asm/i8259.h> 2862306a36Sopenharmony_ci#include <asm/mpic.h> 2962306a36Sopenharmony_ci#include <asm/smp.h> 3062306a36Sopenharmony_ci#include <asm/time.h> 3162306a36Sopenharmony_ci#include <asm/mmu.h> 3262306a36Sopenharmony_ci#include <asm/debug.h> 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci#include <pcmcia/ss.h> 3562306a36Sopenharmony_ci#include <pcmcia/cistpl.h> 3662306a36Sopenharmony_ci#include <pcmcia/ds.h> 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci#include "pasemi.h" 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci/* SDC reset register, must be pre-mapped at reset time */ 4162306a36Sopenharmony_cistatic void __iomem *reset_reg; 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci/* Various error status registers, must be pre-mapped at MCE time */ 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci#define MAX_MCE_REGS 32 4662306a36Sopenharmony_cistruct mce_regs { 4762306a36Sopenharmony_ci char *name; 4862306a36Sopenharmony_ci void __iomem *addr; 4962306a36Sopenharmony_ci}; 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_cistatic struct mce_regs mce_regs[MAX_MCE_REGS]; 5262306a36Sopenharmony_cistatic int num_mce_regs; 5362306a36Sopenharmony_cistatic int nmi_virq = 0; 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_cistatic void __noreturn pas_restart(char *cmd) 5762306a36Sopenharmony_ci{ 5862306a36Sopenharmony_ci /* Need to put others cpu in hold loop so they're not sleeping */ 5962306a36Sopenharmony_ci smp_send_stop(); 6062306a36Sopenharmony_ci udelay(10000); 6162306a36Sopenharmony_ci printk("Restarting...\n"); 6262306a36Sopenharmony_ci while (1) 6362306a36Sopenharmony_ci out_le32(reset_reg, 0x6000000); 6462306a36Sopenharmony_ci} 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci#ifdef CONFIG_PPC_PASEMI_NEMO 6762306a36Sopenharmony_civoid pas_shutdown(void) 6862306a36Sopenharmony_ci{ 6962306a36Sopenharmony_ci /* Set the PLD bit that makes the SB600 think the power button is being pressed */ 7062306a36Sopenharmony_ci void __iomem *pld_map = ioremap(0xf5000000,4096); 7162306a36Sopenharmony_ci while (1) 7262306a36Sopenharmony_ci out_8(pld_map+7,0x01); 7362306a36Sopenharmony_ci} 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci/* RTC platform device structure as is not in device tree */ 7662306a36Sopenharmony_cistatic struct resource rtc_resource[] = {{ 7762306a36Sopenharmony_ci .name = "rtc", 7862306a36Sopenharmony_ci .start = 0x70, 7962306a36Sopenharmony_ci .end = 0x71, 8062306a36Sopenharmony_ci .flags = IORESOURCE_IO, 8162306a36Sopenharmony_ci}, { 8262306a36Sopenharmony_ci .name = "rtc", 8362306a36Sopenharmony_ci .start = 8, 8462306a36Sopenharmony_ci .end = 8, 8562306a36Sopenharmony_ci .flags = IORESOURCE_IRQ, 8662306a36Sopenharmony_ci}}; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_cistatic inline void nemo_init_rtc(void) 8962306a36Sopenharmony_ci{ 9062306a36Sopenharmony_ci platform_device_register_simple("rtc_cmos", -1, rtc_resource, 2); 9162306a36Sopenharmony_ci} 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci#else 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_cistatic inline void nemo_init_rtc(void) 9662306a36Sopenharmony_ci{ 9762306a36Sopenharmony_ci} 9862306a36Sopenharmony_ci#endif 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci#ifdef CONFIG_SMP 10162306a36Sopenharmony_cistatic arch_spinlock_t timebase_lock; 10262306a36Sopenharmony_cistatic unsigned long timebase; 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_cistatic void pas_give_timebase(void) 10562306a36Sopenharmony_ci{ 10662306a36Sopenharmony_ci unsigned long flags; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci local_irq_save(flags); 10962306a36Sopenharmony_ci hard_irq_disable(); 11062306a36Sopenharmony_ci arch_spin_lock(&timebase_lock); 11162306a36Sopenharmony_ci mtspr(SPRN_TBCTL, TBCTL_FREEZE); 11262306a36Sopenharmony_ci isync(); 11362306a36Sopenharmony_ci timebase = get_tb(); 11462306a36Sopenharmony_ci arch_spin_unlock(&timebase_lock); 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci while (timebase) 11762306a36Sopenharmony_ci barrier(); 11862306a36Sopenharmony_ci mtspr(SPRN_TBCTL, TBCTL_RESTART); 11962306a36Sopenharmony_ci local_irq_restore(flags); 12062306a36Sopenharmony_ci} 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_cistatic void pas_take_timebase(void) 12362306a36Sopenharmony_ci{ 12462306a36Sopenharmony_ci while (!timebase) 12562306a36Sopenharmony_ci smp_rmb(); 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci arch_spin_lock(&timebase_lock); 12862306a36Sopenharmony_ci set_tb(timebase >> 32, timebase & 0xffffffff); 12962306a36Sopenharmony_ci timebase = 0; 13062306a36Sopenharmony_ci arch_spin_unlock(&timebase_lock); 13162306a36Sopenharmony_ci} 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_cistatic struct smp_ops_t pas_smp_ops = { 13462306a36Sopenharmony_ci .probe = smp_mpic_probe, 13562306a36Sopenharmony_ci .message_pass = smp_mpic_message_pass, 13662306a36Sopenharmony_ci .kick_cpu = smp_generic_kick_cpu, 13762306a36Sopenharmony_ci .setup_cpu = smp_mpic_setup_cpu, 13862306a36Sopenharmony_ci .give_timebase = pas_give_timebase, 13962306a36Sopenharmony_ci .take_timebase = pas_take_timebase, 14062306a36Sopenharmony_ci}; 14162306a36Sopenharmony_ci#endif /* CONFIG_SMP */ 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_cistatic void __init pas_setup_arch(void) 14462306a36Sopenharmony_ci{ 14562306a36Sopenharmony_ci#ifdef CONFIG_SMP 14662306a36Sopenharmony_ci /* Setup SMP callback */ 14762306a36Sopenharmony_ci smp_ops = &pas_smp_ops; 14862306a36Sopenharmony_ci#endif 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci /* Remap SDC register for doing reset */ 15162306a36Sopenharmony_ci /* XXXOJN This should maybe come out of the device tree */ 15262306a36Sopenharmony_ci reset_reg = ioremap(0xfc101100, 4); 15362306a36Sopenharmony_ci} 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_cistatic int __init pas_setup_mce_regs(void) 15662306a36Sopenharmony_ci{ 15762306a36Sopenharmony_ci struct pci_dev *dev; 15862306a36Sopenharmony_ci int reg; 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci /* Remap various SoC status registers for use by the MCE handler */ 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci reg = 0; 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci dev = pci_get_device(PCI_VENDOR_ID_PASEMI, 0xa00a, NULL); 16562306a36Sopenharmony_ci while (dev && reg < MAX_MCE_REGS) { 16662306a36Sopenharmony_ci mce_regs[reg].name = kasprintf(GFP_KERNEL, 16762306a36Sopenharmony_ci "mc%d_mcdebug_errsta", reg); 16862306a36Sopenharmony_ci mce_regs[reg].addr = pasemi_pci_getcfgaddr(dev, 0x730); 16962306a36Sopenharmony_ci dev = pci_get_device(PCI_VENDOR_ID_PASEMI, 0xa00a, dev); 17062306a36Sopenharmony_ci reg++; 17162306a36Sopenharmony_ci } 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci dev = pci_get_device(PCI_VENDOR_ID_PASEMI, 0xa001, NULL); 17462306a36Sopenharmony_ci if (dev && reg+4 < MAX_MCE_REGS) { 17562306a36Sopenharmony_ci mce_regs[reg].name = "iobdbg_IntStatus1"; 17662306a36Sopenharmony_ci mce_regs[reg].addr = pasemi_pci_getcfgaddr(dev, 0x438); 17762306a36Sopenharmony_ci reg++; 17862306a36Sopenharmony_ci mce_regs[reg].name = "iobdbg_IOCTbusIntDbgReg"; 17962306a36Sopenharmony_ci mce_regs[reg].addr = pasemi_pci_getcfgaddr(dev, 0x454); 18062306a36Sopenharmony_ci reg++; 18162306a36Sopenharmony_ci mce_regs[reg].name = "iobiom_IntStatus"; 18262306a36Sopenharmony_ci mce_regs[reg].addr = pasemi_pci_getcfgaddr(dev, 0xc10); 18362306a36Sopenharmony_ci reg++; 18462306a36Sopenharmony_ci mce_regs[reg].name = "iobiom_IntDbgReg"; 18562306a36Sopenharmony_ci mce_regs[reg].addr = pasemi_pci_getcfgaddr(dev, 0xc1c); 18662306a36Sopenharmony_ci reg++; 18762306a36Sopenharmony_ci } 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci dev = pci_get_device(PCI_VENDOR_ID_PASEMI, 0xa009, NULL); 19062306a36Sopenharmony_ci if (dev && reg+2 < MAX_MCE_REGS) { 19162306a36Sopenharmony_ci mce_regs[reg].name = "l2csts_IntStatus"; 19262306a36Sopenharmony_ci mce_regs[reg].addr = pasemi_pci_getcfgaddr(dev, 0x200); 19362306a36Sopenharmony_ci reg++; 19462306a36Sopenharmony_ci mce_regs[reg].name = "l2csts_Cnt"; 19562306a36Sopenharmony_ci mce_regs[reg].addr = pasemi_pci_getcfgaddr(dev, 0x214); 19662306a36Sopenharmony_ci reg++; 19762306a36Sopenharmony_ci } 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci num_mce_regs = reg; 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci return 0; 20262306a36Sopenharmony_ci} 20362306a36Sopenharmony_cimachine_device_initcall(pasemi, pas_setup_mce_regs); 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci#ifdef CONFIG_PPC_PASEMI_NEMO 20662306a36Sopenharmony_cistatic void sb600_8259_cascade(struct irq_desc *desc) 20762306a36Sopenharmony_ci{ 20862306a36Sopenharmony_ci struct irq_chip *chip = irq_desc_get_chip(desc); 20962306a36Sopenharmony_ci unsigned int cascade_irq = i8259_irq(); 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci if (cascade_irq) 21262306a36Sopenharmony_ci generic_handle_irq(cascade_irq); 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci chip->irq_eoi(&desc->irq_data); 21562306a36Sopenharmony_ci} 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_cistatic void __init nemo_init_IRQ(struct mpic *mpic) 21862306a36Sopenharmony_ci{ 21962306a36Sopenharmony_ci struct device_node *np; 22062306a36Sopenharmony_ci int gpio_virq; 22162306a36Sopenharmony_ci /* Connect the SB600's legacy i8259 controller */ 22262306a36Sopenharmony_ci np = of_find_node_by_path("/pxp@0,e0000000"); 22362306a36Sopenharmony_ci i8259_init(np, 0); 22462306a36Sopenharmony_ci of_node_put(np); 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci gpio_virq = irq_create_mapping(NULL, 3); 22762306a36Sopenharmony_ci irq_set_irq_type(gpio_virq, IRQ_TYPE_LEVEL_HIGH); 22862306a36Sopenharmony_ci irq_set_chained_handler(gpio_virq, sb600_8259_cascade); 22962306a36Sopenharmony_ci mpic_unmask_irq(irq_get_irq_data(gpio_virq)); 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci irq_set_default_host(mpic->irqhost); 23262306a36Sopenharmony_ci} 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci#else 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_cistatic inline void nemo_init_IRQ(struct mpic *mpic) 23762306a36Sopenharmony_ci{ 23862306a36Sopenharmony_ci} 23962306a36Sopenharmony_ci#endif 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_cistatic __init void pas_init_IRQ(void) 24262306a36Sopenharmony_ci{ 24362306a36Sopenharmony_ci struct device_node *np; 24462306a36Sopenharmony_ci struct device_node *root, *mpic_node; 24562306a36Sopenharmony_ci unsigned long openpic_addr; 24662306a36Sopenharmony_ci const unsigned int *opprop; 24762306a36Sopenharmony_ci int naddr, opplen; 24862306a36Sopenharmony_ci int mpic_flags; 24962306a36Sopenharmony_ci const unsigned int *nmiprop; 25062306a36Sopenharmony_ci struct mpic *mpic; 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci mpic_node = NULL; 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci for_each_node_by_type(np, "interrupt-controller") 25562306a36Sopenharmony_ci if (of_device_is_compatible(np, "open-pic")) { 25662306a36Sopenharmony_ci mpic_node = np; 25762306a36Sopenharmony_ci break; 25862306a36Sopenharmony_ci } 25962306a36Sopenharmony_ci if (!mpic_node) 26062306a36Sopenharmony_ci for_each_node_by_type(np, "open-pic") { 26162306a36Sopenharmony_ci mpic_node = np; 26262306a36Sopenharmony_ci break; 26362306a36Sopenharmony_ci } 26462306a36Sopenharmony_ci if (!mpic_node) { 26562306a36Sopenharmony_ci pr_err("Failed to locate the MPIC interrupt controller\n"); 26662306a36Sopenharmony_ci return; 26762306a36Sopenharmony_ci } 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci /* Find address list in /platform-open-pic */ 27062306a36Sopenharmony_ci root = of_find_node_by_path("/"); 27162306a36Sopenharmony_ci naddr = of_n_addr_cells(root); 27262306a36Sopenharmony_ci opprop = of_get_property(root, "platform-open-pic", &opplen); 27362306a36Sopenharmony_ci if (!opprop) { 27462306a36Sopenharmony_ci pr_err("No platform-open-pic property.\n"); 27562306a36Sopenharmony_ci of_node_put(root); 27662306a36Sopenharmony_ci return; 27762306a36Sopenharmony_ci } 27862306a36Sopenharmony_ci openpic_addr = of_read_number(opprop, naddr); 27962306a36Sopenharmony_ci pr_debug("OpenPIC addr: %lx\n", openpic_addr); 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci mpic_flags = MPIC_LARGE_VECTORS | MPIC_NO_BIAS | MPIC_NO_RESET; 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci nmiprop = of_get_property(mpic_node, "nmi-source", NULL); 28462306a36Sopenharmony_ci if (nmiprop) 28562306a36Sopenharmony_ci mpic_flags |= MPIC_ENABLE_MCK; 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci mpic = mpic_alloc(mpic_node, openpic_addr, 28862306a36Sopenharmony_ci mpic_flags, 0, 0, "PASEMI-OPIC"); 28962306a36Sopenharmony_ci BUG_ON(!mpic); 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci mpic_assign_isu(mpic, 0, mpic->paddr + 0x10000); 29262306a36Sopenharmony_ci mpic_init(mpic); 29362306a36Sopenharmony_ci /* The NMI/MCK source needs to be prio 15 */ 29462306a36Sopenharmony_ci if (nmiprop) { 29562306a36Sopenharmony_ci nmi_virq = irq_create_mapping(NULL, *nmiprop); 29662306a36Sopenharmony_ci mpic_irq_set_priority(nmi_virq, 15); 29762306a36Sopenharmony_ci irq_set_irq_type(nmi_virq, IRQ_TYPE_EDGE_RISING); 29862306a36Sopenharmony_ci mpic_unmask_irq(irq_get_irq_data(nmi_virq)); 29962306a36Sopenharmony_ci } 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci nemo_init_IRQ(mpic); 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci of_node_put(mpic_node); 30462306a36Sopenharmony_ci of_node_put(root); 30562306a36Sopenharmony_ci} 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_cistatic void __init pas_progress(char *s, unsigned short hex) 30862306a36Sopenharmony_ci{ 30962306a36Sopenharmony_ci printk("[%04x] : %s\n", hex, s ? s : ""); 31062306a36Sopenharmony_ci} 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_cistatic int pas_machine_check_handler(struct pt_regs *regs) 31462306a36Sopenharmony_ci{ 31562306a36Sopenharmony_ci int cpu = smp_processor_id(); 31662306a36Sopenharmony_ci unsigned long srr0, srr1, dsisr; 31762306a36Sopenharmony_ci int dump_slb = 0; 31862306a36Sopenharmony_ci int i; 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci srr0 = regs->nip; 32162306a36Sopenharmony_ci srr1 = regs->msr; 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci if (nmi_virq && mpic_get_mcirq() == nmi_virq) { 32462306a36Sopenharmony_ci pr_err("NMI delivered\n"); 32562306a36Sopenharmony_ci debugger(regs); 32662306a36Sopenharmony_ci mpic_end_irq(irq_get_irq_data(nmi_virq)); 32762306a36Sopenharmony_ci goto out; 32862306a36Sopenharmony_ci } 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci dsisr = mfspr(SPRN_DSISR); 33162306a36Sopenharmony_ci pr_err("Machine Check on CPU %d\n", cpu); 33262306a36Sopenharmony_ci pr_err("SRR0 0x%016lx SRR1 0x%016lx\n", srr0, srr1); 33362306a36Sopenharmony_ci pr_err("DSISR 0x%016lx DAR 0x%016lx\n", dsisr, regs->dar); 33462306a36Sopenharmony_ci pr_err("BER 0x%016lx MER 0x%016lx\n", mfspr(SPRN_PA6T_BER), 33562306a36Sopenharmony_ci mfspr(SPRN_PA6T_MER)); 33662306a36Sopenharmony_ci pr_err("IER 0x%016lx DER 0x%016lx\n", mfspr(SPRN_PA6T_IER), 33762306a36Sopenharmony_ci mfspr(SPRN_PA6T_DER)); 33862306a36Sopenharmony_ci pr_err("Cause:\n"); 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci if (srr1 & 0x200000) 34162306a36Sopenharmony_ci pr_err("Signalled by SDC\n"); 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci if (srr1 & 0x100000) { 34462306a36Sopenharmony_ci pr_err("Load/Store detected error:\n"); 34562306a36Sopenharmony_ci if (dsisr & 0x8000) 34662306a36Sopenharmony_ci pr_err("D-cache ECC double-bit error or bus error\n"); 34762306a36Sopenharmony_ci if (dsisr & 0x4000) 34862306a36Sopenharmony_ci pr_err("LSU snoop response error\n"); 34962306a36Sopenharmony_ci if (dsisr & 0x2000) { 35062306a36Sopenharmony_ci pr_err("MMU SLB multi-hit or invalid B field\n"); 35162306a36Sopenharmony_ci dump_slb = 1; 35262306a36Sopenharmony_ci } 35362306a36Sopenharmony_ci if (dsisr & 0x1000) 35462306a36Sopenharmony_ci pr_err("Recoverable Duptags\n"); 35562306a36Sopenharmony_ci if (dsisr & 0x800) 35662306a36Sopenharmony_ci pr_err("Recoverable D-cache parity error count overflow\n"); 35762306a36Sopenharmony_ci if (dsisr & 0x400) 35862306a36Sopenharmony_ci pr_err("TLB parity error count overflow\n"); 35962306a36Sopenharmony_ci } 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci if (srr1 & 0x80000) 36262306a36Sopenharmony_ci pr_err("Bus Error\n"); 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci if (srr1 & 0x40000) { 36562306a36Sopenharmony_ci pr_err("I-side SLB multiple hit\n"); 36662306a36Sopenharmony_ci dump_slb = 1; 36762306a36Sopenharmony_ci } 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci if (srr1 & 0x20000) 37062306a36Sopenharmony_ci pr_err("I-cache parity error hit\n"); 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci if (num_mce_regs == 0) 37362306a36Sopenharmony_ci pr_err("No MCE registers mapped yet, can't dump\n"); 37462306a36Sopenharmony_ci else 37562306a36Sopenharmony_ci pr_err("SoC debug registers:\n"); 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci for (i = 0; i < num_mce_regs; i++) 37862306a36Sopenharmony_ci pr_err("%s: 0x%08x\n", mce_regs[i].name, 37962306a36Sopenharmony_ci in_le32(mce_regs[i].addr)); 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci if (dump_slb) { 38262306a36Sopenharmony_ci unsigned long e, v; 38362306a36Sopenharmony_ci int i; 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci pr_err("slb contents:\n"); 38662306a36Sopenharmony_ci for (i = 0; i < mmu_slb_size; i++) { 38762306a36Sopenharmony_ci asm volatile("slbmfee %0,%1" : "=r" (e) : "r" (i)); 38862306a36Sopenharmony_ci asm volatile("slbmfev %0,%1" : "=r" (v) : "r" (i)); 38962306a36Sopenharmony_ci pr_err("%02d %016lx %016lx\n", i, e, v); 39062306a36Sopenharmony_ci } 39162306a36Sopenharmony_ci } 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ciout: 39462306a36Sopenharmony_ci /* SRR1[62] is from MSR[62] if recoverable, so pass that back */ 39562306a36Sopenharmony_ci return !!(srr1 & 0x2); 39662306a36Sopenharmony_ci} 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_cistatic const struct of_device_id pasemi_bus_ids[] = { 39962306a36Sopenharmony_ci /* Unfortunately needed for legacy firmwares */ 40062306a36Sopenharmony_ci { .type = "localbus", }, 40162306a36Sopenharmony_ci { .type = "sdc", }, 40262306a36Sopenharmony_ci /* These are the proper entries, which newer firmware uses */ 40362306a36Sopenharmony_ci { .compatible = "pasemi,localbus", }, 40462306a36Sopenharmony_ci { .compatible = "pasemi,sdc", }, 40562306a36Sopenharmony_ci {}, 40662306a36Sopenharmony_ci}; 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_cistatic int __init pasemi_publish_devices(void) 40962306a36Sopenharmony_ci{ 41062306a36Sopenharmony_ci /* Publish OF platform devices for SDC and other non-PCI devices */ 41162306a36Sopenharmony_ci of_platform_bus_probe(NULL, pasemi_bus_ids, NULL); 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci nemo_init_rtc(); 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci return 0; 41662306a36Sopenharmony_ci} 41762306a36Sopenharmony_cimachine_device_initcall(pasemi, pasemi_publish_devices); 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci/* 42162306a36Sopenharmony_ci * Called very early, MMU is off, device-tree isn't unflattened 42262306a36Sopenharmony_ci */ 42362306a36Sopenharmony_cistatic int __init pas_probe(void) 42462306a36Sopenharmony_ci{ 42562306a36Sopenharmony_ci if (!of_machine_is_compatible("PA6T-1682M") && 42662306a36Sopenharmony_ci !of_machine_is_compatible("pasemi,pwrficient")) 42762306a36Sopenharmony_ci return 0; 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci#ifdef CONFIG_PPC_PASEMI_NEMO 43062306a36Sopenharmony_ci /* 43162306a36Sopenharmony_ci * Check for the Nemo motherboard here, if we are running on one 43262306a36Sopenharmony_ci * change the machine definition to fit 43362306a36Sopenharmony_ci */ 43462306a36Sopenharmony_ci if (of_machine_is_compatible("pasemi,nemo")) { 43562306a36Sopenharmony_ci pm_power_off = pas_shutdown; 43662306a36Sopenharmony_ci ppc_md.name = "A-EON Amigaone X1000"; 43762306a36Sopenharmony_ci } 43862306a36Sopenharmony_ci#endif 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci iommu_init_early_pasemi(); 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci return 1; 44362306a36Sopenharmony_ci} 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_cidefine_machine(pasemi) { 44662306a36Sopenharmony_ci .name = "PA Semi PWRficient", 44762306a36Sopenharmony_ci .probe = pas_probe, 44862306a36Sopenharmony_ci .setup_arch = pas_setup_arch, 44962306a36Sopenharmony_ci .discover_phbs = pas_pci_init, 45062306a36Sopenharmony_ci .init_IRQ = pas_init_IRQ, 45162306a36Sopenharmony_ci .get_irq = mpic_get_irq, 45262306a36Sopenharmony_ci .restart = pas_restart, 45362306a36Sopenharmony_ci .get_boot_time = pas_get_boot_time, 45462306a36Sopenharmony_ci .progress = pas_progress, 45562306a36Sopenharmony_ci .machine_check_exception = pas_machine_check_handler, 45662306a36Sopenharmony_ci}; 457