162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Board setup routines for the Motorola/Emerson MVME5100. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright 2013 CSC Australia Pty. Ltd. 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Based on earlier code by: 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * Matt Porter, MontaVista Software Inc. 1062306a36Sopenharmony_ci * Copyright 2001 MontaVista Software Inc. 1162306a36Sopenharmony_ci * 1262306a36Sopenharmony_ci * Author: Stephen Chivers <schivers@csc.com> 1362306a36Sopenharmony_ci */ 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#include <linux/of_irq.h> 1662306a36Sopenharmony_ci#include <linux/of_platform.h> 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#include <asm/i8259.h> 1962306a36Sopenharmony_ci#include <asm/pci-bridge.h> 2062306a36Sopenharmony_ci#include <asm/mpic.h> 2162306a36Sopenharmony_ci#include <mm/mmu_decl.h> 2262306a36Sopenharmony_ci#include <asm/udbg.h> 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#define HAWK_MPIC_SIZE 0x00040000U 2562306a36Sopenharmony_ci#define MVME5100_PCI_MEM_OFFSET 0x00000000 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci/* Board register addresses. */ 2862306a36Sopenharmony_ci#define BOARD_STATUS_REG 0xfef88080 2962306a36Sopenharmony_ci#define BOARD_MODFAIL_REG 0xfef88090 3062306a36Sopenharmony_ci#define BOARD_MODRST_REG 0xfef880a0 3162306a36Sopenharmony_ci#define BOARD_TBEN_REG 0xfef880c0 3262306a36Sopenharmony_ci#define BOARD_SW_READ_REG 0xfef880e0 3362306a36Sopenharmony_ci#define BOARD_GEO_ADDR_REG 0xfef880e8 3462306a36Sopenharmony_ci#define BOARD_EXT_FEATURE1_REG 0xfef880f0 3562306a36Sopenharmony_ci#define BOARD_EXT_FEATURE2_REG 0xfef88100 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_cistatic phys_addr_t pci_membase; 3862306a36Sopenharmony_cistatic u_char *restart; 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_cistatic void mvme5100_8259_cascade(struct irq_desc *desc) 4162306a36Sopenharmony_ci{ 4262306a36Sopenharmony_ci struct irq_chip *chip = irq_desc_get_chip(desc); 4362306a36Sopenharmony_ci unsigned int cascade_irq = i8259_irq(); 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci if (cascade_irq) 4662306a36Sopenharmony_ci generic_handle_irq(cascade_irq); 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci chip->irq_eoi(&desc->irq_data); 4962306a36Sopenharmony_ci} 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_cistatic void __init mvme5100_pic_init(void) 5262306a36Sopenharmony_ci{ 5362306a36Sopenharmony_ci struct mpic *mpic; 5462306a36Sopenharmony_ci struct device_node *np; 5562306a36Sopenharmony_ci struct device_node *cp = NULL; 5662306a36Sopenharmony_ci unsigned int cirq; 5762306a36Sopenharmony_ci unsigned long intack = 0; 5862306a36Sopenharmony_ci const u32 *prop = NULL; 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci np = of_find_node_by_type(NULL, "open-pic"); 6162306a36Sopenharmony_ci if (!np) { 6262306a36Sopenharmony_ci pr_err("Could not find open-pic node\n"); 6362306a36Sopenharmony_ci return; 6462306a36Sopenharmony_ci } 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci mpic = mpic_alloc(np, pci_membase, 0, 16, 256, " OpenPIC "); 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci BUG_ON(mpic == NULL); 6962306a36Sopenharmony_ci of_node_put(np); 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci mpic_assign_isu(mpic, 0, pci_membase + 0x10000); 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci mpic_init(mpic); 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci cp = of_find_compatible_node(NULL, NULL, "chrp,iic"); 7662306a36Sopenharmony_ci if (cp == NULL) { 7762306a36Sopenharmony_ci pr_warn("mvme5100_pic_init: couldn't find i8259\n"); 7862306a36Sopenharmony_ci return; 7962306a36Sopenharmony_ci } 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci cirq = irq_of_parse_and_map(cp, 0); 8262306a36Sopenharmony_ci if (!cirq) { 8362306a36Sopenharmony_ci pr_warn("mvme5100_pic_init: no cascade interrupt?\n"); 8462306a36Sopenharmony_ci return; 8562306a36Sopenharmony_ci } 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci np = of_find_compatible_node(NULL, "pci", "mpc10x-pci"); 8862306a36Sopenharmony_ci if (np) { 8962306a36Sopenharmony_ci prop = of_get_property(np, "8259-interrupt-acknowledge", NULL); 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci if (prop) 9262306a36Sopenharmony_ci intack = prop[0]; 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci of_node_put(np); 9562306a36Sopenharmony_ci } 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci if (intack) 9862306a36Sopenharmony_ci pr_debug("mvme5100_pic_init: PCI 8259 intack at 0x%016lx\n", 9962306a36Sopenharmony_ci intack); 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci i8259_init(cp, intack); 10262306a36Sopenharmony_ci of_node_put(cp); 10362306a36Sopenharmony_ci irq_set_chained_handler(cirq, mvme5100_8259_cascade); 10462306a36Sopenharmony_ci} 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_cistatic int __init mvme5100_add_bridge(struct device_node *dev) 10762306a36Sopenharmony_ci{ 10862306a36Sopenharmony_ci const int *bus_range; 10962306a36Sopenharmony_ci int len; 11062306a36Sopenharmony_ci struct pci_controller *hose; 11162306a36Sopenharmony_ci unsigned short devid; 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci pr_info("Adding PCI host bridge %pOF\n", dev); 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci bus_range = of_get_property(dev, "bus-range", &len); 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci hose = pcibios_alloc_controller(dev); 11862306a36Sopenharmony_ci if (hose == NULL) 11962306a36Sopenharmony_ci return -ENOMEM; 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci hose->first_busno = bus_range ? bus_range[0] : 0; 12262306a36Sopenharmony_ci hose->last_busno = bus_range ? bus_range[1] : 0xff; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci setup_indirect_pci(hose, 0xfe000cf8, 0xfe000cfc, 0); 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci pci_process_bridge_OF_ranges(hose, dev, 1); 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci early_read_config_word(hose, 0, 0, PCI_DEVICE_ID, &devid); 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci if (devid != PCI_DEVICE_ID_MOTOROLA_HAWK) { 13162306a36Sopenharmony_ci pr_err("HAWK PHB not present?\n"); 13262306a36Sopenharmony_ci return 0; 13362306a36Sopenharmony_ci } 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci early_read_config_dword(hose, 0, 0, PCI_BASE_ADDRESS_1, &pci_membase); 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci if (pci_membase == 0) { 13862306a36Sopenharmony_ci pr_err("HAWK PHB mibar not correctly set?\n"); 13962306a36Sopenharmony_ci return 0; 14062306a36Sopenharmony_ci } 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci pr_info("mvme5100_pic_init: pci_membase: %x\n", pci_membase); 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci return 0; 14562306a36Sopenharmony_ci} 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_cistatic const struct of_device_id mvme5100_of_bus_ids[] __initconst = { 14862306a36Sopenharmony_ci { .compatible = "hawk-bridge", }, 14962306a36Sopenharmony_ci {}, 15062306a36Sopenharmony_ci}; 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci/* 15362306a36Sopenharmony_ci * Setup the architecture 15462306a36Sopenharmony_ci */ 15562306a36Sopenharmony_cistatic void __init mvme5100_setup_arch(void) 15662306a36Sopenharmony_ci{ 15762306a36Sopenharmony_ci if (ppc_md.progress) 15862306a36Sopenharmony_ci ppc_md.progress("mvme5100_setup_arch()", 0); 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci restart = ioremap(BOARD_MODRST_REG, 4); 16162306a36Sopenharmony_ci} 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_cistatic void __init mvme5100_setup_pci(void) 16462306a36Sopenharmony_ci{ 16562306a36Sopenharmony_ci struct device_node *np; 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci for_each_compatible_node(np, "pci", "hawk-pci") 16862306a36Sopenharmony_ci mvme5100_add_bridge(np); 16962306a36Sopenharmony_ci} 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_cistatic void mvme5100_show_cpuinfo(struct seq_file *m) 17262306a36Sopenharmony_ci{ 17362306a36Sopenharmony_ci seq_puts(m, "Vendor\t\t: Motorola/Emerson\n"); 17462306a36Sopenharmony_ci seq_puts(m, "Machine\t\t: MVME5100\n"); 17562306a36Sopenharmony_ci} 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_cistatic void __noreturn mvme5100_restart(char *cmd) 17862306a36Sopenharmony_ci{ 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci local_irq_disable(); 18162306a36Sopenharmony_ci mtmsr(mfmsr() | MSR_IP); 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci out_8((u_char *) restart, 0x01); 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci while (1) 18662306a36Sopenharmony_ci ; 18762306a36Sopenharmony_ci} 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_cistatic int __init probe_of_platform_devices(void) 19062306a36Sopenharmony_ci{ 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci of_platform_bus_probe(NULL, mvme5100_of_bus_ids, NULL); 19362306a36Sopenharmony_ci return 0; 19462306a36Sopenharmony_ci} 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_cimachine_device_initcall(mvme5100, probe_of_platform_devices); 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_cidefine_machine(mvme5100) { 19962306a36Sopenharmony_ci .name = "MVME5100", 20062306a36Sopenharmony_ci .compatible = "MVME5100", 20162306a36Sopenharmony_ci .setup_arch = mvme5100_setup_arch, 20262306a36Sopenharmony_ci .discover_phbs = mvme5100_setup_pci, 20362306a36Sopenharmony_ci .init_IRQ = mvme5100_pic_init, 20462306a36Sopenharmony_ci .show_cpuinfo = mvme5100_show_cpuinfo, 20562306a36Sopenharmony_ci .get_irq = mpic_get_irq, 20662306a36Sopenharmony_ci .restart = mvme5100_restart, 20762306a36Sopenharmony_ci .progress = udbg_progress, 20862306a36Sopenharmony_ci}; 209