diff options
Diffstat (limited to 'arch/powerpc/platforms/embedded6xx/mvme5100.c')
| -rw-r--r-- | arch/powerpc/platforms/embedded6xx/mvme5100.c | 221 | 
1 files changed, 221 insertions, 0 deletions
diff --git a/arch/powerpc/platforms/embedded6xx/mvme5100.c b/arch/powerpc/platforms/embedded6xx/mvme5100.c new file mode 100644 index 00000000000..25e3bfb64ef --- /dev/null +++ b/arch/powerpc/platforms/embedded6xx/mvme5100.c @@ -0,0 +1,221 @@ +/* + * 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; +} + +static struct of_device_id mvme5100_of_bus_ids[] __initdata = { +	{ .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, +};  | 
