/* * 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 #include #include #include #include #include #include #include #include #include #include #include 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) { unsigned long root = of_get_flat_dt_root(); if (of_flat_dt_is_compatible(root, "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, };