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 31 #include <asm/prom.h> 32 #include <asm/system.h> 33 #include <asm/iommu.h> 34 #include <asm/machdep.h> 35 #include <asm/mpic.h> 36 #include <asm/smp.h> 37 #include <asm/time.h> 38 39 #include "pasemi.h" 40 41 static void __iomem *reset_reg; 42 43 static void pas_restart(char *cmd) 44 { 45 printk("Restarting...\n"); 46 while (1) 47 out_le32(reset_reg, 0x6000000); 48 } 49 50 #ifdef CONFIG_SMP 51 static DEFINE_SPINLOCK(timebase_lock); 52 53 static void __devinit pas_give_timebase(void) 54 { 55 unsigned long tb; 56 57 spin_lock(&timebase_lock); 58 mtspr(SPRN_TBCTL, TBCTL_FREEZE); 59 tb = mftb(); 60 mtspr(SPRN_TBCTL, TBCTL_UPDATE_LOWER | (tb & 0xffffffff)); 61 mtspr(SPRN_TBCTL, TBCTL_UPDATE_UPPER | (tb >> 32)); 62 mtspr(SPRN_TBCTL, TBCTL_RESTART); 63 spin_unlock(&timebase_lock); 64 pr_debug("pas_give_timebase: cpu %d gave tb %lx\n", 65 smp_processor_id(), tb); 66 } 67 68 static void __devinit pas_take_timebase(void) 69 { 70 pr_debug("pas_take_timebase: cpu %d has tb %lx\n", 71 smp_processor_id(), mftb()); 72 } 73 74 struct smp_ops_t pas_smp_ops = { 75 .probe = smp_mpic_probe, 76 .message_pass = smp_mpic_message_pass, 77 .kick_cpu = smp_generic_kick_cpu, 78 .setup_cpu = smp_mpic_setup_cpu, 79 .give_timebase = pas_give_timebase, 80 .take_timebase = pas_take_timebase, 81 }; 82 #endif /* CONFIG_SMP */ 83 84 void __init pas_setup_arch(void) 85 { 86 #ifdef CONFIG_SMP 87 /* Setup SMP callback */ 88 smp_ops = &pas_smp_ops; 89 #endif 90 /* Lookup PCI hosts */ 91 pas_pci_init(); 92 93 #ifdef CONFIG_DUMMY_CONSOLE 94 conswitchp = &dummy_con; 95 #endif 96 97 /* Remap SDC register for doing reset */ 98 /* XXXOJN This should maybe come out of the device tree */ 99 reset_reg = ioremap(0xfc101100, 4); 100 101 pasemi_idle_init(); 102 } 103 104 /* No legacy IO on our parts */ 105 static int pas_check_legacy_ioport(unsigned int baseport) 106 { 107 return -ENODEV; 108 } 109 110 static __init void pas_init_IRQ(void) 111 { 112 struct device_node *np; 113 struct device_node *root, *mpic_node; 114 unsigned long openpic_addr; 115 const unsigned int *opprop; 116 int naddr, opplen; 117 struct mpic *mpic; 118 119 mpic_node = NULL; 120 121 for_each_node_by_type(np, "interrupt-controller") 122 if (device_is_compatible(np, "open-pic")) { 123 mpic_node = np; 124 break; 125 } 126 if (!mpic_node) 127 for_each_node_by_type(np, "open-pic") { 128 mpic_node = np; 129 break; 130 } 131 if (!mpic_node) { 132 printk(KERN_ERR 133 "Failed to locate the MPIC interrupt controller\n"); 134 return; 135 } 136 137 /* Find address list in /platform-open-pic */ 138 root = of_find_node_by_path("/"); 139 naddr = prom_n_addr_cells(root); 140 opprop = get_property(root, "platform-open-pic", &opplen); 141 if (!opprop) { 142 printk(KERN_ERR "No platform-open-pic property.\n"); 143 of_node_put(root); 144 return; 145 } 146 openpic_addr = of_read_number(opprop, naddr); 147 printk(KERN_DEBUG "OpenPIC addr: %lx\n", openpic_addr); 148 149 mpic = mpic_alloc(mpic_node, openpic_addr, 150 MPIC_PRIMARY|MPIC_LARGE_VECTORS, 151 0, 0, " PAS-OPIC "); 152 BUG_ON(!mpic); 153 154 mpic_assign_isu(mpic, 0, openpic_addr + 0x10000); 155 mpic_init(mpic); 156 of_node_put(mpic_node); 157 of_node_put(root); 158 } 159 160 static void __init pas_progress(char *s, unsigned short hex) 161 { 162 printk("[%04x] : %s\n", hex, s ? s : ""); 163 } 164 165 166 static int pas_machine_check_handler(struct pt_regs *regs) 167 { 168 int cpu = smp_processor_id(); 169 unsigned long srr0, srr1, dsisr; 170 171 srr0 = regs->nip; 172 srr1 = regs->msr; 173 dsisr = mfspr(SPRN_DSISR); 174 printk(KERN_ERR "Machine Check on CPU %d\n", cpu); 175 printk(KERN_ERR "SRR0 0x%016lx SRR1 0x%016lx\n", srr0, srr1); 176 printk(KERN_ERR "DSISR 0x%016lx DAR 0x%016lx\n", dsisr, regs->dar); 177 printk(KERN_ERR "Cause:\n"); 178 179 if (srr1 & 0x200000) 180 printk(KERN_ERR "Signalled by SDC\n"); 181 if (srr1 & 0x100000) { 182 printk(KERN_ERR "Load/Store detected error:\n"); 183 if (dsisr & 0x8000) 184 printk(KERN_ERR "D-cache ECC double-bit error or bus error\n"); 185 if (dsisr & 0x4000) 186 printk(KERN_ERR "LSU snoop response error\n"); 187 if (dsisr & 0x2000) 188 printk(KERN_ERR "MMU SLB multi-hit or invalid B field\n"); 189 if (dsisr & 0x1000) 190 printk(KERN_ERR "Recoverable Duptags\n"); 191 if (dsisr & 0x800) 192 printk(KERN_ERR "Recoverable D-cache parity error count overflow\n"); 193 if (dsisr & 0x400) 194 printk(KERN_ERR "TLB parity error count overflow\n"); 195 } 196 if (srr1 & 0x80000) 197 printk(KERN_ERR "Bus Error\n"); 198 if (srr1 & 0x40000) 199 printk(KERN_ERR "I-side SLB multiple hit\n"); 200 if (srr1 & 0x20000) 201 printk(KERN_ERR "I-cache parity error hit\n"); 202 203 /* SRR1[62] is from MSR[62] if recoverable, so pass that back */ 204 return !!(srr1 & 0x2); 205 } 206 207 static void __init pas_init_early(void) 208 { 209 iommu_init_early_pasemi(); 210 } 211 212 213 /* 214 * Called very early, MMU is off, device-tree isn't unflattened 215 */ 216 static int __init pas_probe(void) 217 { 218 unsigned long root = of_get_flat_dt_root(); 219 220 if (!of_flat_dt_is_compatible(root, "PA6T-1682M")) 221 return 0; 222 223 hpte_init_native(); 224 225 alloc_iobmap_l2(); 226 227 return 1; 228 } 229 230 define_machine(pas) { 231 .name = "PA Semi PA6T-1682M", 232 .probe = pas_probe, 233 .setup_arch = pas_setup_arch, 234 .init_early = pas_init_early, 235 .init_IRQ = pas_init_IRQ, 236 .get_irq = mpic_get_irq, 237 .restart = pas_restart, 238 .get_boot_time = pas_get_boot_time, 239 .calibrate_decr = generic_calibrate_decr, 240 .check_legacy_ioport = pas_check_legacy_ioport, 241 .progress = pas_progress, 242 .machine_check_exception = pas_machine_check_handler, 243 .pci_irq_fixup = pas_pci_irq_fixup, 244 }; 245