fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / arch / arm / mach-ixp2000 / ixdp2800.c
index 285eaf0..70d247f 100644 (file)
@@ -14,7 +14,6 @@
  *  Free Software Foundation;  either version 2 of the  License, or (at your
  *  option) any later version.
  */
-#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/mm.h>
@@ -23,9 +22,6 @@
 #include <linux/device.h>
 #include <linux/bitops.h>
 #include <linux/pci.h>
-#include <linux/interrupt.h>
-#include <linux/mm.h>
-#include <linux/init.h>
 #include <linux/ioport.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
 #include <asm/mach/flash.h>
 #include <asm/mach/arch.h>
 
-
-void ixdp2400_init_irq(void)
-{
-       ixdp2x00_init_irq(IXDP2800_CPLD_INT_STAT, IXDP2800_CPLD_INT_MASK, IXDP2400_NR_IRQS);
-}
-
 /*************************************************************************
  * IXDP2800 timer tick
  *************************************************************************/
 
-static void __init ixdp2800_init_time(void)
+static void __init ixdp2800_timer_init(void)
 {
        ixp2000_init_time(50000000);
 }
 
+static struct sys_timer ixdp2800_timer = {
+       .init           = ixdp2800_timer_init,
+       .offset         = ixp2000_gettimeoffset,
+};
+
 /*************************************************************************
  * IXDP2800 PCI
  *************************************************************************/
+static void __init ixdp2800_slave_disable_pci_master(void)
+{
+       *IXP2000_PCI_CMDSTAT &= ~(PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY);
+}
+
+static void __init ixdp2800_master_wait_for_slave(void)
+{
+       volatile u32 *addr;
+
+       printk(KERN_INFO "IXDP2800: waiting for slave NPU to configure "
+                        "its BAR sizes\n");
+
+       addr = ixp2000_pci_config_addr(0, IXDP2X00_SLAVE_NPU_DEVFN,
+                                       PCI_BASE_ADDRESS_1);
+       do {
+               *addr = 0xffffffff;
+               cpu_relax();
+       } while (*addr != 0xfe000008);
+
+       addr = ixp2000_pci_config_addr(0, IXDP2X00_SLAVE_NPU_DEVFN,
+                                       PCI_BASE_ADDRESS_2);
+       do {
+               *addr = 0xffffffff;
+               cpu_relax();
+       } while (*addr != 0xc0000008);
+
+       /*
+        * Configure the slave's SDRAM BAR by hand.
+        */
+       *addr = 0x40000008;
+}
+
+static void __init ixdp2800_slave_wait_for_master_enable(void)
+{
+       printk(KERN_INFO "IXDP2800: waiting for master NPU to enable us\n");
+
+       while ((*IXP2000_PCI_CMDSTAT & PCI_COMMAND_MASTER) == 0)
+               cpu_relax();
+}
+
 void __init ixdp2800_pci_preinit(void)
 {
        printk("ixdp2x00_pci_preinit called\n");
 
-       *IXP2000_PCI_ADDR_EXT =  0x0000e000;
+       *IXP2000_PCI_ADDR_EXT = 0x0001e000;
+
+       if (!ixdp2x00_master_npu())
+               ixdp2800_slave_disable_pci_master();
 
-       *IXP2000_PCI_DRAM_BASE_ADDR_MASK = (0x40000000 - 1) & ~0xfffff;
        *IXP2000_PCI_SRAM_BASE_ADDR_MASK = (0x2000000 - 1) & ~0x3ffff;
+       *IXP2000_PCI_DRAM_BASE_ADDR_MASK = (0x40000000 - 1) & ~0xfffff;
 
        ixp2000_pci_preinit();
+
+       if (ixdp2x00_master_npu()) {
+               /*
+                * Wait until the slave set its SRAM/SDRAM BAR sizes
+                * correctly before we proceed to scan and enumerate
+                * the bus.
+                */
+               ixdp2800_master_wait_for_slave();
+
+               /*
+                * We configure the SDRAM BARs by hand because they
+                * are 1G and fall outside of the regular allocated
+                * PCI address space.
+                */
+               *IXP2000_PCI_SDRAM_BAR = 0x00000008;
+       } else {
+               /*
+                * Wait for the master to complete scanning the bus
+                * and assigning resources before we proceed to scan
+                * the bus ourselves.  Set pci=firmware to honor the
+                * master's resource assignment.
+                */
+               ixdp2800_slave_wait_for_master_enable();
+               pcibios_setup("firmware");
+       }
 }
 
-int ixdp2800_pci_setup(int nr, struct pci_sys_data *sys)
+/*
+ * We assign the SDRAM BARs for the two IXP2800 CPUs by hand, outside
+ * of the regular PCI window, because there's only 512M of outbound PCI
+ * memory window on each IXP, while we need 1G for each of the BARs.
+ */
+static void __devinit ixp2800_pci_fixup(struct pci_dev *dev)
+{
+       if (machine_is_ixdp2800()) {
+               dev->resource[2].start = 0;
+               dev->resource[2].end   = 0;
+               dev->resource[2].flags = 0;
+       }
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IXP2800, ixp2800_pci_fixup);
+
+static int __init ixdp2800_pci_setup(int nr, struct pci_sys_data *sys)
 {
        sys->mem_offset = 0x00000000;
 
@@ -111,7 +189,7 @@ static int __init ixdp2800_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
                 * Device behind the first bridge
                 */
                if(dev->bus->self->devfn == IXDP2X00_P2P_DEVFN) {
-                       switch(PCI_SLOT(dev->devfn)) {
+                       switch(dev->devfn) {
                                case IXDP2X00_PMC_DEVFN:
                                        return IRQ_IXDP2800_PMC;        
                        
@@ -127,22 +205,47 @@ static int __init ixdp2800_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
        } else return IRQ_IXP2000_PCIB; /* Slave NIC interrupt */
 }
 
-static void ixdp2800_pci_postinit(void)
+static void __init ixdp2800_master_enable_slave(void)
 {
-       struct pci_dev *dev;
+       volatile u32 *addr;
 
-       if (ixdp2x00_master_npu()) {
-               dev = pci_find_slot(1, IXDP2800_SLAVE_ENET_DEVFN);
-               pci_remove_bus_device(dev);
-       } else {
-               dev = pci_find_slot(1, IXDP2800_MASTER_ENET_DEVFN);
-               pci_remove_bus_device(dev);
+       printk(KERN_INFO "IXDP2800: enabling slave NPU\n");
+
+       addr = (volatile u32 *)ixp2000_pci_config_addr(0,
+                                       IXDP2X00_SLAVE_NPU_DEVFN,
+                                       PCI_COMMAND);
 
+       *addr |= PCI_COMMAND_MASTER;
+}
+
+static void __init ixdp2800_master_wait_for_slave_bus_scan(void)
+{
+       volatile u32 *addr;
+
+       printk(KERN_INFO "IXDP2800: waiting for slave to finish bus scan\n");
+
+       addr = (volatile u32 *)ixp2000_pci_config_addr(0,
+                                       IXDP2X00_SLAVE_NPU_DEVFN,
+                                       PCI_COMMAND);
+       while ((*addr & PCI_COMMAND_MEMORY) == 0)
+               cpu_relax();
+}
+
+static void __init ixdp2800_slave_signal_bus_scan_completion(void)
+{
+       printk(KERN_INFO "IXDP2800: bus scan done, signaling master\n");
+       *IXP2000_PCI_CMDSTAT |= PCI_COMMAND_MEMORY;
+}
+
+static void __init ixdp2800_pci_postinit(void)
+{
+       if (!ixdp2x00_master_npu()) {
                ixdp2x00_slave_pci_postinit();
+               ixdp2800_slave_signal_bus_scan_completion();
        }
 }
 
-struct hw_pci ixdp2800_pci __initdata = {
+struct __initdata hw_pci ixdp2800_pci __initdata = {
        .nr_controllers = 1,
        .setup          = ixdp2800_pci_setup,
        .preinit        = ixdp2800_pci_preinit,
@@ -153,8 +256,23 @@ struct hw_pci ixdp2800_pci __initdata = {
 
 int __init ixdp2800_pci_init(void)
 {
-       if (machine_is_ixdp2800())
+       if (machine_is_ixdp2800()) {
+               struct pci_dev *dev;
+
                pci_common_init(&ixdp2800_pci);
+               if (ixdp2x00_master_npu()) {
+                       dev = pci_get_bus_and_slot(1, IXDP2800_SLAVE_ENET_DEVFN);
+                       pci_remove_bus_device(dev);
+                       pci_dev_put(dev);
+
+                       ixdp2800_master_enable_slave();
+                       ixdp2800_master_wait_for_slave_bus_scan();
+               } else {
+                       dev = pci_get_bus_and_slot(1, IXDP2800_MASTER_ENET_DEVFN);
+                       pci_remove_bus_device(dev);
+                       pci_dev_put(dev);
+               }
+       }
 
        return 0;
 }
@@ -167,12 +285,13 @@ void ixdp2800_init_irq(void)
 }
 
 MACHINE_START(IXDP2800, "Intel IXDP2800 Development Platform")
-       MAINTAINER("MontaVista Software, Inc.")
-       BOOT_MEM(0x00000000, IXP2000_UART_PHYS_BASE, IXP2000_UART_VIRT_BASE)
-       BOOT_PARAMS(0x00000100)
-       MAPIO(ixdp2x00_map_io)
-       INITIRQ(ixdp2800_init_irq)
-       INITTIME(ixdp2800_init_time)
-       INIT_MACHINE(ixdp2x00_init_machine)
+       /* Maintainer: MontaVista Software, Inc. */
+       .phys_io        = IXP2000_UART_PHYS_BASE,
+       .io_pg_offst    = ((IXP2000_UART_VIRT_BASE) >> 18) & 0xfffc,
+       .boot_params    = 0x00000100,
+       .map_io         = ixdp2x00_map_io,
+       .init_irq       = ixdp2800_init_irq,
+       .timer          = &ixdp2800_timer,
+       .init_machine   = ixdp2x00_init_machine,
 MACHINE_END