| 
									
										
										
										
											2014-01-09 13:01:22 +11:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * Board setup routines for the Motorola/Emerson MVME5100. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Copyright 2013 CSC Australia Pty. Ltd. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Based on earlier code by: | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *    Matt Porter, MontaVista Software Inc. | 
					
						
							|  |  |  |  *    Copyright 2001 MontaVista Software Inc. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This program is free software; you can redistribute  it and/or modify it | 
					
						
							|  |  |  |  * under  the terms of  the GNU General  Public License as published by the | 
					
						
							|  |  |  |  * Free Software Foundation;  either version 2 of the  License, or (at your | 
					
						
							|  |  |  |  * option) any later version. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Author: Stephen Chivers <schivers@csc.com> | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <linux/of_platform.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <asm/i8259.h>
 | 
					
						
							|  |  |  | #include <asm/pci-bridge.h>
 | 
					
						
							|  |  |  | #include <asm/mpic.h>
 | 
					
						
							|  |  |  | #include <asm/prom.h>
 | 
					
						
							|  |  |  | #include <mm/mmu_decl.h>
 | 
					
						
							|  |  |  | #include <asm/udbg.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define HAWK_MPIC_SIZE		0x00040000U
 | 
					
						
							|  |  |  | #define MVME5100_PCI_MEM_OFFSET 0x00000000
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Board register addresses. */ | 
					
						
							|  |  |  | #define BOARD_STATUS_REG	0xfef88080
 | 
					
						
							|  |  |  | #define BOARD_MODFAIL_REG	0xfef88090
 | 
					
						
							|  |  |  | #define BOARD_MODRST_REG	0xfef880a0
 | 
					
						
							|  |  |  | #define BOARD_TBEN_REG		0xfef880c0
 | 
					
						
							|  |  |  | #define BOARD_SW_READ_REG	0xfef880e0
 | 
					
						
							|  |  |  | #define BOARD_GEO_ADDR_REG	0xfef880e8
 | 
					
						
							|  |  |  | #define BOARD_EXT_FEATURE1_REG	0xfef880f0
 | 
					
						
							|  |  |  | #define BOARD_EXT_FEATURE2_REG	0xfef88100
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static phys_addr_t pci_membase; | 
					
						
							|  |  |  | static u_char *restart; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void mvme5100_8259_cascade(unsigned int irq, struct irq_desc *desc) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct irq_chip *chip = irq_desc_get_chip(desc); | 
					
						
							|  |  |  | 	unsigned int cascade_irq = i8259_irq(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (cascade_irq != NO_IRQ) | 
					
						
							|  |  |  | 		generic_handle_irq(cascade_irq); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	chip->irq_eoi(&desc->irq_data); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void __init mvme5100_pic_init(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct mpic *mpic; | 
					
						
							|  |  |  | 	struct device_node *np; | 
					
						
							|  |  |  | 	struct device_node *cp = NULL; | 
					
						
							|  |  |  | 	unsigned int cirq; | 
					
						
							|  |  |  | 	unsigned long intack = 0; | 
					
						
							|  |  |  | 	const u32 *prop = NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	np = of_find_node_by_type(NULL, "open-pic"); | 
					
						
							|  |  |  | 	if (!np) { | 
					
						
							|  |  |  | 		pr_err("Could not find open-pic node\n"); | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	mpic = mpic_alloc(np, pci_membase, 0, 16, 256, " OpenPIC  "); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	BUG_ON(mpic == NULL); | 
					
						
							|  |  |  | 	of_node_put(np); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	mpic_assign_isu(mpic, 0, pci_membase + 0x10000); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	mpic_init(mpic); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	cp = of_find_compatible_node(NULL, NULL, "chrp,iic"); | 
					
						
							|  |  |  | 	if (cp == NULL) { | 
					
						
							|  |  |  | 		pr_warn("mvme5100_pic_init: couldn't find i8259\n"); | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	cirq = irq_of_parse_and_map(cp, 0); | 
					
						
							|  |  |  | 	if (cirq == NO_IRQ) { | 
					
						
							|  |  |  | 		pr_warn("mvme5100_pic_init: no cascade interrupt?\n"); | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	np = of_find_compatible_node(NULL, "pci", "mpc10x-pci"); | 
					
						
							|  |  |  | 	if (np) { | 
					
						
							|  |  |  | 		prop = of_get_property(np, "8259-interrupt-acknowledge", NULL); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (prop) | 
					
						
							|  |  |  | 			intack = prop[0]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		of_node_put(np); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (intack) | 
					
						
							|  |  |  | 		pr_debug("mvme5100_pic_init: PCI 8259 intack at 0x%016lx\n", | 
					
						
							|  |  |  | 		   intack); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	i8259_init(cp, intack); | 
					
						
							|  |  |  | 	of_node_put(cp); | 
					
						
							|  |  |  | 	irq_set_chained_handler(cirq, mvme5100_8259_cascade); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int __init mvme5100_add_bridge(struct device_node *dev) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	const int		*bus_range; | 
					
						
							|  |  |  | 	int			len; | 
					
						
							|  |  |  | 	struct pci_controller	*hose; | 
					
						
							|  |  |  | 	unsigned short		devid; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	pr_info("Adding PCI host bridge %s\n", dev->full_name); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	bus_range = of_get_property(dev, "bus-range", &len); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	hose = pcibios_alloc_controller(dev); | 
					
						
							|  |  |  | 	if (hose == NULL) | 
					
						
							|  |  |  | 		return -ENOMEM; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	hose->first_busno = bus_range ? bus_range[0] : 0; | 
					
						
							|  |  |  | 	hose->last_busno = bus_range ? bus_range[1] : 0xff; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	setup_indirect_pci(hose, 0xfe000cf8, 0xfe000cfc, 0); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	pci_process_bridge_OF_ranges(hose, dev, 1); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	early_read_config_word(hose, 0, 0, PCI_DEVICE_ID, &devid); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (devid != PCI_DEVICE_ID_MOTOROLA_HAWK) { | 
					
						
							|  |  |  | 		pr_err("HAWK PHB not present?\n"); | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	early_read_config_dword(hose, 0, 0, PCI_BASE_ADDRESS_1, &pci_membase); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (pci_membase == 0) { | 
					
						
							|  |  |  | 		pr_err("HAWK PHB mibar not correctly set?\n"); | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	pr_info("mvme5100_pic_init: pci_membase: %x\n", pci_membase); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-09-10 21:56:38 +02:00
										 |  |  | static const struct of_device_id mvme5100_of_bus_ids[] __initconst = { | 
					
						
							| 
									
										
										
										
											2014-01-09 13:01:22 +11:00
										 |  |  | 	{ .compatible = "hawk-bridge", }, | 
					
						
							|  |  |  | 	{}, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * Setup the architecture | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static void __init mvme5100_setup_arch(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct device_node *np; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (ppc_md.progress) | 
					
						
							|  |  |  | 		ppc_md.progress("mvme5100_setup_arch()", 0); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for_each_compatible_node(np, "pci", "hawk-pci") | 
					
						
							|  |  |  | 		mvme5100_add_bridge(np); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	restart = ioremap(BOARD_MODRST_REG, 4); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void mvme5100_show_cpuinfo(struct seq_file *m) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	seq_puts(m, "Vendor\t\t: Motorola/Emerson\n"); | 
					
						
							|  |  |  | 	seq_puts(m, "Machine\t\t: MVME5100\n"); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void mvme5100_restart(char *cmd) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	local_irq_disable(); | 
					
						
							|  |  |  | 	mtmsr(mfmsr() | MSR_IP); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	out_8((u_char *) restart, 0x01); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	while (1) | 
					
						
							|  |  |  | 		; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * Called very early, device-tree isn't unflattened | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static int __init mvme5100_probe(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	unsigned long root = of_get_flat_dt_root(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return of_flat_dt_is_compatible(root, "MVME5100"); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int __init probe_of_platform_devices(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	of_platform_bus_probe(NULL, mvme5100_of_bus_ids, NULL); | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | machine_device_initcall(mvme5100, probe_of_platform_devices); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | define_machine(mvme5100) { | 
					
						
							|  |  |  | 	.name			= "MVME5100", | 
					
						
							|  |  |  | 	.probe			= mvme5100_probe, | 
					
						
							|  |  |  | 	.setup_arch		= mvme5100_setup_arch, | 
					
						
							|  |  |  | 	.init_IRQ		= mvme5100_pic_init, | 
					
						
							|  |  |  | 	.show_cpuinfo		= mvme5100_show_cpuinfo, | 
					
						
							|  |  |  | 	.get_irq		= mpic_get_irq, | 
					
						
							|  |  |  | 	.restart		= mvme5100_restart, | 
					
						
							|  |  |  | 	.calibrate_decr		= generic_calibrate_decr, | 
					
						
							|  |  |  | 	.progress		= udbg_progress, | 
					
						
							|  |  |  | }; |