aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm
diff options
context:
space:
mode:
authorLennert Buytenhek <buytenh@org.rmk.(none)>2005-04-29 17:13:57 -0400
committerRussell King <rmk+kernel@arm.linux.org.uk>2005-04-29 17:13:57 -0400
commit53e173f62c318e65e6ae13524b04c5cf38c1bc3c (patch)
treefc09c64720880b4a3634b63ebf8f072a1510945b /arch/arm
parentca315159dfa80a2bfc7d917a717a7ee8d771bdf9 (diff)
[PATCH] ARM: 2660/2: fix ixdp2800 boot and pci init
Patch from Lennert Buytenhek The IXDP2800 is an evalution platform for the IXP2800 processor that has two IXP2800s connected to the same PCI bus. This is problematic as both CPUs will try to configure the PCI bus as they boot linux. Contrary to on the other IXP2000 platforms, the boot loader on the IXDP2800 doesn't configure the PCI bus properly, so we do want the linux instance on one of the CPUs to do that. Making one of the CPUs ignore the PCI bus (and thus act like a pure PCI slave device) is not an option because there is a 82559 NIC on the PCI bus for each of the CPUs. The chosen solution is to have the master CPU configure the PCI bus while the slave is kept in a quiescent state, and then to have the slave CPU scan the PCI bus (without assigning resources) while the master is kept in a quiescent state. After this ritual, the master deletes the slave NIC from its PCI device list, the slave deletes the master NIC from its device list, and (almost) all is well. There's still one little problem: each of the CPUs has a 1G SDRAM BAR, but the IXP2000 only has 512M of outbound PCI memory window. We solve this by hand-assigning the master and slave SDRAM BARs to a location outside each of the IXP's outbound PCI windows, and by having the rest of the BARs autoconfigured in the outbound PCI windows, in the range [e0000000..ffffffff], so that there is a 1:1 pci:phys mapping between them. Even with this patch, a number of issues still remain -- just imagine what happens if one of the CPUs is rebooted, by watchdog or by hand, but the other one isn't. But those issues are not easily fixable given the strange PCI layout of this board and the behavior of the boot loader shipped with the platform. Signed-off-by: Lennert Buytenhek Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'arch/arm')
-rw-r--r--arch/arm/configs/ixdp2800_defconfig2
-rw-r--r--arch/arm/mach-ixp2000/ixdp2800.c147
2 files changed, 135 insertions, 14 deletions
diff --git a/arch/arm/configs/ixdp2800_defconfig b/arch/arm/configs/ixdp2800_defconfig
index d36f99192962..7be3521f91fc 100644
--- a/arch/arm/configs/ixdp2800_defconfig
+++ b/arch/arm/configs/ixdp2800_defconfig
@@ -133,7 +133,7 @@ CONFIG_ALIGNMENT_TRAP=y
133# 133#
134CONFIG_ZBOOT_ROM_TEXT=0x0 134CONFIG_ZBOOT_ROM_TEXT=0x0
135CONFIG_ZBOOT_ROM_BSS=0x0 135CONFIG_ZBOOT_ROM_BSS=0x0
136CONFIG_CMDLINE="console=ttyS0,9600 root=/dev/nfs ip=bootp mem=64M@0x0 pci=firmware" 136CONFIG_CMDLINE="console=ttyS0,9600 root=/dev/nfs ip=bootp mem=64M@0x0"
137# CONFIG_XIP_KERNEL is not set 137# CONFIG_XIP_KERNEL is not set
138 138
139# 139#
diff --git a/arch/arm/mach-ixp2000/ixdp2800.c b/arch/arm/mach-ixp2000/ixdp2800.c
index c4683aaff84a..aec13c7108a9 100644
--- a/arch/arm/mach-ixp2000/ixdp2800.c
+++ b/arch/arm/mach-ixp2000/ixdp2800.c
@@ -65,19 +65,102 @@ static struct sys_timer ixdp2800_timer = {
65/************************************************************************* 65/*************************************************************************
66 * IXDP2800 PCI 66 * IXDP2800 PCI
67 *************************************************************************/ 67 *************************************************************************/
68static void __init ixdp2800_slave_disable_pci_master(void)
69{
70 *IXP2000_PCI_CMDSTAT &= ~(PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY);
71}
72
73static void __init ixdp2800_master_wait_for_slave(void)
74{
75 volatile u32 *addr;
76
77 printk(KERN_INFO "IXDP2800: waiting for slave NPU to configure "
78 "its BAR sizes\n");
79
80 addr = ixp2000_pci_config_addr(0, IXDP2X00_SLAVE_NPU_DEVFN,
81 PCI_BASE_ADDRESS_1);
82 do {
83 *addr = 0xffffffff;
84 cpu_relax();
85 } while (*addr != 0xfe000008);
86
87 addr = ixp2000_pci_config_addr(0, IXDP2X00_SLAVE_NPU_DEVFN,
88 PCI_BASE_ADDRESS_2);
89 do {
90 *addr = 0xffffffff;
91 cpu_relax();
92 } while (*addr != 0xc0000008);
93
94 /*
95 * Configure the slave's SDRAM BAR by hand.
96 */
97 *addr = 0x40000008;
98}
99
100static void __init ixdp2800_slave_wait_for_master_enable(void)
101{
102 printk(KERN_INFO "IXDP2800: waiting for master NPU to enable us\n");
103
104 while ((*IXP2000_PCI_CMDSTAT & PCI_COMMAND_MASTER) == 0)
105 cpu_relax();
106}
107
68void __init ixdp2800_pci_preinit(void) 108void __init ixdp2800_pci_preinit(void)
69{ 109{
70 printk("ixdp2x00_pci_preinit called\n"); 110 printk("ixdp2x00_pci_preinit called\n");
71 111
72 *IXP2000_PCI_ADDR_EXT = 0x0000e000; 112 *IXP2000_PCI_ADDR_EXT = 0x0001e000;
113
114 if (!ixdp2x00_master_npu())
115 ixdp2800_slave_disable_pci_master();
73 116
74 *IXP2000_PCI_DRAM_BASE_ADDR_MASK = (0x40000000 - 1) & ~0xfffff;
75 *IXP2000_PCI_SRAM_BASE_ADDR_MASK = (0x2000000 - 1) & ~0x3ffff; 117 *IXP2000_PCI_SRAM_BASE_ADDR_MASK = (0x2000000 - 1) & ~0x3ffff;
118 *IXP2000_PCI_DRAM_BASE_ADDR_MASK = (0x40000000 - 1) & ~0xfffff;
76 119
77 ixp2000_pci_preinit(); 120 ixp2000_pci_preinit();
121
122 if (ixdp2x00_master_npu()) {
123 /*
124 * Wait until the slave set its SRAM/SDRAM BAR sizes
125 * correctly before we proceed to scan and enumerate
126 * the bus.
127 */
128 ixdp2800_master_wait_for_slave();
129
130 /*
131 * We configure the SDRAM BARs by hand because they
132 * are 1G and fall outside of the regular allocated
133 * PCI address space.
134 */
135 *IXP2000_PCI_SDRAM_BAR = 0x00000008;
136 } else {
137 /*
138 * Wait for the master to complete scanning the bus
139 * and assigning resources before we proceed to scan
140 * the bus ourselves. Set pci=firmware to honor the
141 * master's resource assignment.
142 */
143 ixdp2800_slave_wait_for_master_enable();
144 pcibios_setup("firmware");
145 }
78} 146}
79 147
80int ixdp2800_pci_setup(int nr, struct pci_sys_data *sys) 148/*
149 * We assign the SDRAM BARs for the two IXP2800 CPUs by hand, outside
150 * of the regular PCI window, because there's only 512M of outbound PCI
151 * memory window on each IXP, while we need 1G for each of the BARs.
152 */
153static void __devinit ixp2800_pci_fixup(struct pci_dev *dev)
154{
155 if (machine_is_ixdp2800()) {
156 dev->resource[2].start = 0;
157 dev->resource[2].end = 0;
158 dev->resource[2].flags = 0;
159 }
160}
161DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IXP2800, ixp2800_pci_fixup);
162
163static int __init ixdp2800_pci_setup(int nr, struct pci_sys_data *sys)
81{ 164{
82 sys->mem_offset = 0x00000000; 165 sys->mem_offset = 0x00000000;
83 166
@@ -129,22 +212,47 @@ static int __init ixdp2800_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
129 } else return IRQ_IXP2000_PCIB; /* Slave NIC interrupt */ 212 } else return IRQ_IXP2000_PCIB; /* Slave NIC interrupt */
130} 213}
131 214
132static void ixdp2800_pci_postinit(void) 215static void __init ixdp2800_master_enable_slave(void)
133{ 216{
134 struct pci_dev *dev; 217 volatile u32 *addr;
135 218
136 if (ixdp2x00_master_npu()) { 219 printk(KERN_INFO "IXDP2800: enabling slave NPU\n");
137 dev = pci_find_slot(1, IXDP2800_SLAVE_ENET_DEVFN); 220
138 pci_remove_bus_device(dev); 221 addr = (volatile u32 *)ixp2000_pci_config_addr(0,
139 } else { 222 IXDP2X00_SLAVE_NPU_DEVFN,
140 dev = pci_find_slot(1, IXDP2800_MASTER_ENET_DEVFN); 223 PCI_COMMAND);
141 pci_remove_bus_device(dev); 224
225 *addr |= PCI_COMMAND_MASTER;
226}
142 227
228static void __init ixdp2800_master_wait_for_slave_bus_scan(void)
229{
230 volatile u32 *addr;
231
232 printk(KERN_INFO "IXDP2800: waiting for slave to finish bus scan\n");
233
234 addr = (volatile u32 *)ixp2000_pci_config_addr(0,
235 IXDP2X00_SLAVE_NPU_DEVFN,
236 PCI_COMMAND);
237 while ((*addr & PCI_COMMAND_MEMORY) == 0)
238 cpu_relax();
239}
240
241static void __init ixdp2800_slave_signal_bus_scan_completion(void)
242{
243 printk(KERN_INFO "IXDP2800: bus scan done, signaling master\n");
244 *IXP2000_PCI_CMDSTAT |= PCI_COMMAND_MEMORY;
245}
246
247static void __init ixdp2800_pci_postinit(void)
248{
249 if (!ixdp2x00_master_npu()) {
143 ixdp2x00_slave_pci_postinit(); 250 ixdp2x00_slave_pci_postinit();
251 ixdp2800_slave_signal_bus_scan_completion();
144 } 252 }
145} 253}
146 254
147struct hw_pci ixdp2800_pci __initdata = { 255struct __initdata hw_pci ixdp2800_pci __initdata = {
148 .nr_controllers = 1, 256 .nr_controllers = 1,
149 .setup = ixdp2800_pci_setup, 257 .setup = ixdp2800_pci_setup,
150 .preinit = ixdp2800_pci_preinit, 258 .preinit = ixdp2800_pci_preinit,
@@ -155,8 +263,21 @@ struct hw_pci ixdp2800_pci __initdata = {
155 263
156int __init ixdp2800_pci_init(void) 264int __init ixdp2800_pci_init(void)
157{ 265{
158 if (machine_is_ixdp2800()) 266 if (machine_is_ixdp2800()) {
267 struct pci_dev *dev;
268
159 pci_common_init(&ixdp2800_pci); 269 pci_common_init(&ixdp2800_pci);
270 if (ixdp2x00_master_npu()) {
271 dev = pci_find_slot(1, IXDP2800_SLAVE_ENET_DEVFN);
272 pci_remove_bus_device(dev);
273
274 ixdp2800_master_enable_slave();
275 ixdp2800_master_wait_for_slave_bus_scan();
276 } else {
277 dev = pci_find_slot(1, IXDP2800_MASTER_ENET_DEVFN);
278 pci_remove_bus_device(dev);
279 }
280 }
160 281
161 return 0; 282 return 0;
162} 283}