| /* |
| * 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, |
| }; |