| /* | |
| * AmigaOne platform setup | |
| * | |
| * Copyright 2008 Gerhard Pircher (gerhard_pircher@gmx.net) | |
| * | |
| * Based on original amigaone_setup.c source code | |
| * Copyright 2003 by Hans-Joerg Frieden and Thomas Frieden | |
| * | |
| * 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. | |
| */ | |
| #include <linux/kernel.h> | |
| #include <linux/of.h> | |
| #include <linux/of_address.h> | |
| #include <linux/seq_file.h> | |
| #include <generated/utsrelease.h> | |
| #include <asm/machdep.h> | |
| #include <asm/cputable.h> | |
| #include <asm/pci-bridge.h> | |
| #include <asm/i8259.h> | |
| #include <asm/time.h> | |
| #include <asm/udbg.h> | |
| #include <asm/dma.h> | |
| extern void __flush_disable_L1(void); | |
| void amigaone_show_cpuinfo(struct seq_file *m) | |
| { | |
| seq_printf(m, "vendor\t\t: Eyetech Ltd.\n"); | |
| } | |
| static int __init amigaone_add_bridge(struct device_node *dev) | |
| { | |
| const u32 *cfg_addr, *cfg_data; | |
| int len; | |
| const int *bus_range; | |
| struct pci_controller *hose; | |
| printk(KERN_INFO "Adding PCI host bridge %s\n", dev->full_name); | |
| cfg_addr = of_get_address(dev, 0, NULL, NULL); | |
| cfg_data = of_get_address(dev, 1, NULL, NULL); | |
| if ((cfg_addr == NULL) || (cfg_data == NULL)) | |
| return -ENODEV; | |
| bus_range = of_get_property(dev, "bus-range", &len); | |
| if ((bus_range == NULL) || (len < 2 * sizeof(int))) | |
| printk(KERN_WARNING "Can't get bus-range for %s, assume" | |
| " bus 0\n", dev->full_name); | |
| 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, cfg_addr[0], cfg_data[0], 0); | |
| /* Interpret the "ranges" property */ | |
| /* This also maps the I/O region and sets isa_io/mem_base */ | |
| pci_process_bridge_OF_ranges(hose, dev, 1); | |
| return 0; | |
| } | |
| void __init amigaone_setup_arch(void) | |
| { | |
| struct device_node *np; | |
| int phb = -ENODEV; | |
| /* Lookup PCI host bridges. */ | |
| for_each_compatible_node(np, "pci", "mai-logic,articia-s") | |
| phb = amigaone_add_bridge(np); | |
| BUG_ON(phb != 0); | |
| if (ppc_md.progress) | |
| ppc_md.progress("Linux/PPC "UTS_RELEASE"\n", 0); | |
| } | |
| void __init amigaone_init_IRQ(void) | |
| { | |
| struct device_node *pic, *np = NULL; | |
| const unsigned long *prop = NULL; | |
| unsigned long int_ack = 0; | |
| /* Search for ISA interrupt controller. */ | |
| pic = of_find_compatible_node(NULL, "interrupt-controller", | |
| "pnpPNP,000"); | |
| BUG_ON(pic == NULL); | |
| /* Look for interrupt acknowledge address in the PCI root node. */ | |
| np = of_find_compatible_node(NULL, "pci", "mai-logic,articia-s"); | |
| if (np) { | |
| prop = of_get_property(np, "8259-interrupt-acknowledge", NULL); | |
| if (prop) | |
| int_ack = prop[0]; | |
| of_node_put(np); | |
| } | |
| if (int_ack == 0) | |
| printk(KERN_WARNING "Cannot find PCI interrupt acknowledge" | |
| " address, polling\n"); | |
| i8259_init(pic, int_ack); | |
| ppc_md.get_irq = i8259_irq; | |
| irq_set_default_host(i8259_get_host()); | |
| } | |
| static int __init request_isa_regions(void) | |
| { | |
| request_region(0x00, 0x20, "dma1"); | |
| request_region(0x40, 0x20, "timer"); | |
| request_region(0x80, 0x10, "dma page reg"); | |
| request_region(0xc0, 0x20, "dma2"); | |
| return 0; | |
| } | |
| machine_device_initcall(amigaone, request_isa_regions); | |
| void __noreturn amigaone_restart(char *cmd) | |
| { | |
| local_irq_disable(); | |
| /* Flush and disable caches. */ | |
| __flush_disable_L1(); | |
| /* Set SRR0 to the reset vector and turn on MSR_IP. */ | |
| mtspr(SPRN_SRR0, 0xfff00100); | |
| mtspr(SPRN_SRR1, MSR_IP); | |
| /* Do an rfi to jump back to firmware. */ | |
| __asm__ __volatile__("rfi" : : : "memory"); | |
| /* Not reached. */ | |
| while (1); | |
| } | |
| static int __init amigaone_probe(void) | |
| { | |
| if (of_machine_is_compatible("eyetech,amigaone")) { | |
| /* | |
| * Coherent memory access cause complete system lockup! Thus | |
| * disable this CPU feature, even if the CPU needs it. | |
| */ | |
| cur_cpu_spec->cpu_features &= ~CPU_FTR_NEED_COHERENT; | |
| ISA_DMA_THRESHOLD = 0x00ffffff; | |
| DMA_MODE_READ = 0x44; | |
| DMA_MODE_WRITE = 0x48; | |
| return 1; | |
| } | |
| return 0; | |
| } | |
| define_machine(amigaone) { | |
| .name = "AmigaOne", | |
| .probe = amigaone_probe, | |
| .setup_arch = amigaone_setup_arch, | |
| .show_cpuinfo = amigaone_show_cpuinfo, | |
| .init_IRQ = amigaone_init_IRQ, | |
| .restart = amigaone_restart, | |
| .calibrate_decr = generic_calibrate_decr, | |
| .progress = udbg_progress, | |
| }; |