1 /* 2 * Board setup routines for the Motorola/Emerson MVME5100. 3 * 4 * Copyright 2013 CSC Australia Pty. Ltd. 5 * 6 * Based on earlier code by: 7 * 8 * Matt Porter, MontaVista Software Inc. 9 * Copyright 2001 MontaVista Software Inc. 10 * 11 * This program is free software; you can redistribute it and/or modify it 12 * under the terms of the GNU General Public License as published by the 13 * Free Software Foundation; either version 2 of the License, or (at your 14 * option) any later version. 15 * 16 * Author: Stephen Chivers <schivers@csc.com> 17 * 18 */ 19 20 #include <linux/of_platform.h> 21 22 #include <asm/i8259.h> 23 #include <asm/pci-bridge.h> 24 #include <asm/mpic.h> 25 #include <asm/prom.h> 26 #include <mm/mmu_decl.h> 27 #include <asm/udbg.h> 28 29 #define HAWK_MPIC_SIZE 0x00040000U 30 #define MVME5100_PCI_MEM_OFFSET 0x00000000 31 32 /* Board register addresses. */ 33 #define BOARD_STATUS_REG 0xfef88080 34 #define BOARD_MODFAIL_REG 0xfef88090 35 #define BOARD_MODRST_REG 0xfef880a0 36 #define BOARD_TBEN_REG 0xfef880c0 37 #define BOARD_SW_READ_REG 0xfef880e0 38 #define BOARD_GEO_ADDR_REG 0xfef880e8 39 #define BOARD_EXT_FEATURE1_REG 0xfef880f0 40 #define BOARD_EXT_FEATURE2_REG 0xfef88100 41 42 static phys_addr_t pci_membase; 43 static u_char *restart; 44 45 static void mvme5100_8259_cascade(struct irq_desc *desc) 46 { 47 struct irq_chip *chip = irq_desc_get_chip(desc); 48 unsigned int cascade_irq = i8259_irq(); 49 50 if (cascade_irq) 51 generic_handle_irq(cascade_irq); 52 53 chip->irq_eoi(&desc->irq_data); 54 } 55 56 static void __init mvme5100_pic_init(void) 57 { 58 struct mpic *mpic; 59 struct device_node *np; 60 struct device_node *cp = NULL; 61 unsigned int cirq; 62 unsigned long intack = 0; 63 const u32 *prop = NULL; 64 65 np = of_find_node_by_type(NULL, "open-pic"); 66 if (!np) { 67 pr_err("Could not find open-pic node\n"); 68 return; 69 } 70 71 mpic = mpic_alloc(np, pci_membase, 0, 16, 256, " OpenPIC "); 72 73 BUG_ON(mpic == NULL); 74 of_node_put(np); 75 76 mpic_assign_isu(mpic, 0, pci_membase + 0x10000); 77 78 mpic_init(mpic); 79 80 cp = of_find_compatible_node(NULL, NULL, "chrp,iic"); 81 if (cp == NULL) { 82 pr_warn("mvme5100_pic_init: couldn't find i8259\n"); 83 return; 84 } 85 86 cirq = irq_of_parse_and_map(cp, 0); 87 if (!cirq) { 88 pr_warn("mvme5100_pic_init: no cascade interrupt?\n"); 89 return; 90 } 91 92 np = of_find_compatible_node(NULL, "pci", "mpc10x-pci"); 93 if (np) { 94 prop = of_get_property(np, "8259-interrupt-acknowledge", NULL); 95 96 if (prop) 97 intack = prop[0]; 98 99 of_node_put(np); 100 } 101 102 if (intack) 103 pr_debug("mvme5100_pic_init: PCI 8259 intack at 0x%016lx\n", 104 intack); 105 106 i8259_init(cp, intack); 107 of_node_put(cp); 108 irq_set_chained_handler(cirq, mvme5100_8259_cascade); 109 } 110 111 static int __init mvme5100_add_bridge(struct device_node *dev) 112 { 113 const int *bus_range; 114 int len; 115 struct pci_controller *hose; 116 unsigned short devid; 117 118 pr_info("Adding PCI host bridge %pOF\n", dev); 119 120 bus_range = of_get_property(dev, "bus-range", &len); 121 122 hose = pcibios_alloc_controller(dev); 123 if (hose == NULL) 124 return -ENOMEM; 125 126 hose->first_busno = bus_range ? bus_range[0] : 0; 127 hose->last_busno = bus_range ? bus_range[1] : 0xff; 128 129 setup_indirect_pci(hose, 0xfe000cf8, 0xfe000cfc, 0); 130 131 pci_process_bridge_OF_ranges(hose, dev, 1); 132 133 early_read_config_word(hose, 0, 0, PCI_DEVICE_ID, &devid); 134 135 if (devid != PCI_DEVICE_ID_MOTOROLA_HAWK) { 136 pr_err("HAWK PHB not present?\n"); 137 return 0; 138 } 139 140 early_read_config_dword(hose, 0, 0, PCI_BASE_ADDRESS_1, &pci_membase); 141 142 if (pci_membase == 0) { 143 pr_err("HAWK PHB mibar not correctly set?\n"); 144 return 0; 145 } 146 147 pr_info("mvme5100_pic_init: pci_membase: %x\n", pci_membase); 148 149 return 0; 150 } 151 152 static const struct of_device_id mvme5100_of_bus_ids[] __initconst = { 153 { .compatible = "hawk-bridge", }, 154 {}, 155 }; 156 157 /* 158 * Setup the architecture 159 */ 160 static void __init mvme5100_setup_arch(void) 161 { 162 struct device_node *np; 163 164 if (ppc_md.progress) 165 ppc_md.progress("mvme5100_setup_arch()", 0); 166 167 for_each_compatible_node(np, "pci", "hawk-pci") 168 mvme5100_add_bridge(np); 169 170 restart = ioremap(BOARD_MODRST_REG, 4); 171 } 172 173 174 static void mvme5100_show_cpuinfo(struct seq_file *m) 175 { 176 seq_puts(m, "Vendor\t\t: Motorola/Emerson\n"); 177 seq_puts(m, "Machine\t\t: MVME5100\n"); 178 } 179 180 static void __noreturn mvme5100_restart(char *cmd) 181 { 182 183 local_irq_disable(); 184 mtmsr(mfmsr() | MSR_IP); 185 186 out_8((u_char *) restart, 0x01); 187 188 while (1) 189 ; 190 } 191 192 /* 193 * Called very early, device-tree isn't unflattened 194 */ 195 static int __init mvme5100_probe(void) 196 { 197 return of_machine_is_compatible("MVME5100"); 198 } 199 200 static int __init probe_of_platform_devices(void) 201 { 202 203 of_platform_bus_probe(NULL, mvme5100_of_bus_ids, NULL); 204 return 0; 205 } 206 207 machine_device_initcall(mvme5100, probe_of_platform_devices); 208 209 define_machine(mvme5100) { 210 .name = "MVME5100", 211 .probe = mvme5100_probe, 212 .setup_arch = mvme5100_setup_arch, 213 .init_IRQ = mvme5100_pic_init, 214 .show_cpuinfo = mvme5100_show_cpuinfo, 215 .get_irq = mpic_get_irq, 216 .restart = mvme5100_restart, 217 .calibrate_decr = generic_calibrate_decr, 218 .progress = udbg_progress, 219 }; 220