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