1/* 2 * arch/arm/mach-ixp2000/ixdp2x00.c 3 * 4 * Code common to IXDP2400 and IXDP2800 platforms. 5 * 6 * Original Author: Naeem Afzal <naeem.m.afzal@intel.com> 7 * Maintainer: Deepak Saxena <dsaxena@plexity.net> 8 * 9 * Copyright (C) 2002 Intel Corp. 10 * Copyright (C) 2003-2004 MontaVista Software, Inc. 11 * 12 * This program is free software; you can redistribute it and/or modify it 13 * under the terms of the GNU General Public License as published by the 14 * Free Software Foundation; either version 2 of the License, or (at your 15 * option) any later version. 16 */ 17#include <linux/kernel.h> 18#include <linux/init.h> 19#include <linux/mm.h> 20#include <linux/sched.h> 21#include <linux/interrupt.h> 22#include <linux/platform_device.h> 23#include <linux/bitops.h> 24#include <linux/pci.h> 25#include <linux/ioport.h> 26#include <linux/slab.h> 27#include <linux/delay.h> 28 29#include <asm/io.h> 30#include <asm/irq.h> 31#include <asm/pgtable.h> 32#include <asm/page.h> 33#include <asm/system.h> 34#include <asm/hardware.h> 35#include <asm/mach-types.h> 36 37#include <asm/mach/pci.h> 38#include <asm/mach/map.h> 39#include <asm/mach/irq.h> 40#include <asm/mach/time.h> 41#include <asm/mach/flash.h> 42#include <asm/mach/arch.h> 43 44#include <asm/arch/gpio.h> 45 46 47/************************************************************************* 48 * IXDP2x00 IRQ Initialization 49 *************************************************************************/ 50static volatile unsigned long *board_irq_mask; 51static volatile unsigned long *board_irq_stat; 52static unsigned long board_irq_count; 53 54#ifdef CONFIG_ARCH_IXDP2400 55/* 56 * Slowport configuration for accessing CPLD registers on IXDP2x00 57 */ 58static struct slowport_cfg slowport_cpld_cfg = { 59 .CCR = SLOWPORT_CCR_DIV_2, 60 .WTC = 0x00000070, 61 .RTC = 0x00000070, 62 .PCR = SLOWPORT_MODE_FLASH, 63 .ADC = SLOWPORT_ADDR_WIDTH_24 | SLOWPORT_DATA_WIDTH_8 64}; 65#endif 66 67static void ixdp2x00_irq_mask(unsigned int irq) 68{ 69 unsigned long dummy; 70 static struct slowport_cfg old_cfg; 71 72 /* 73 * This is ugly in common code but really don't know 74 * of a better way to handle it. :( 75 */ 76#ifdef CONFIG_ARCH_IXDP2400 77 if (machine_is_ixdp2400()) 78 ixp2000_acquire_slowport(&slowport_cpld_cfg, &old_cfg); 79#endif 80 81 dummy = *board_irq_mask; 82 dummy |= IXP2000_BOARD_IRQ_MASK(irq); 83 ixp2000_reg_wrb(board_irq_mask, dummy); 84 85#ifdef CONFIG_ARCH_IXDP2400 86 if (machine_is_ixdp2400()) 87 ixp2000_release_slowport(&old_cfg); 88#endif 89} 90 91static void ixdp2x00_irq_unmask(unsigned int irq) 92{ 93 unsigned long dummy; 94 static struct slowport_cfg old_cfg; 95 96#ifdef CONFIG_ARCH_IXDP2400 97 if (machine_is_ixdp2400()) 98 ixp2000_acquire_slowport(&slowport_cpld_cfg, &old_cfg); 99#endif 100 101 dummy = *board_irq_mask; 102 dummy &= ~IXP2000_BOARD_IRQ_MASK(irq); 103 ixp2000_reg_wrb(board_irq_mask, dummy); 104 105 if (machine_is_ixdp2400()) 106 ixp2000_release_slowport(&old_cfg); 107} 108 109static void ixdp2x00_irq_handler(unsigned int irq, struct irq_desc *desc) 110{ 111 volatile u32 ex_interrupt = 0; 112 static struct slowport_cfg old_cfg; 113 int i; 114 115 desc->chip->mask(irq); 116 117#ifdef CONFIG_ARCH_IXDP2400 118 if (machine_is_ixdp2400()) 119 ixp2000_acquire_slowport(&slowport_cpld_cfg, &old_cfg); 120#endif 121 ex_interrupt = *board_irq_stat & 0xff; 122 if (machine_is_ixdp2400()) 123 ixp2000_release_slowport(&old_cfg); 124 125 if(!ex_interrupt) { 126 printk(KERN_ERR "Spurious IXDP2x00 CPLD interrupt!\n"); 127 return; 128 } 129 130 for(i = 0; i < board_irq_count; i++) { 131 if(ex_interrupt & (1 << i)) { 132 struct irq_desc *cpld_desc; 133 int cpld_irq = IXP2000_BOARD_IRQ(0) + i; 134 cpld_desc = irq_desc + cpld_irq; 135 desc_handle_irq(cpld_irq, cpld_desc); 136 } 137 } 138 139 desc->chip->unmask(irq); 140} 141 142static struct irq_chip ixdp2x00_cpld_irq_chip = { 143 .ack = ixdp2x00_irq_mask, 144 .mask = ixdp2x00_irq_mask, 145 .unmask = ixdp2x00_irq_unmask 146}; 147 148void __init ixdp2x00_init_irq(volatile unsigned long *stat_reg, volatile unsigned long *mask_reg, unsigned long nr_irqs) 149{ 150 unsigned int irq; 151 152 ixp2000_init_irq(); 153 154 if (!ixdp2x00_master_npu()) 155 return; 156 157 board_irq_stat = stat_reg; 158 board_irq_mask = mask_reg; 159 board_irq_count = nr_irqs; 160 161 *board_irq_mask = 0xffffffff; 162 163 for(irq = IXP2000_BOARD_IRQ(0); irq < IXP2000_BOARD_IRQ(board_irq_count); irq++) { 164 set_irq_chip(irq, &ixdp2x00_cpld_irq_chip); 165 set_irq_handler(irq, handle_level_irq); 166 set_irq_flags(irq, IRQF_VALID); 167 } 168 169 /* Hook into PCI interrupt */ 170 set_irq_chained_handler(IRQ_IXP2000_PCIB, ixdp2x00_irq_handler); 171} 172 173/************************************************************************* 174 * IXDP2x00 memory map 175 *************************************************************************/ 176static struct map_desc ixdp2x00_io_desc __initdata = { 177 .virtual = IXDP2X00_VIRT_CPLD_BASE, 178 .pfn = __phys_to_pfn(IXDP2X00_PHYS_CPLD_BASE), 179 .length = IXDP2X00_CPLD_SIZE, 180 .type = MT_DEVICE 181}; 182 183void __init ixdp2x00_map_io(void) 184{ 185 ixp2000_map_io(); 186 187 iotable_init(&ixdp2x00_io_desc, 1); 188} 189 190/************************************************************************* 191 * IXDP2x00-common PCI init 192 * 193 * The IXDP2[48]00 has a horrid PCI bus layout. Basically the board 194 * contains two NPUs (ingress and egress) connected over PCI, both running 195 * instances of the kernel. So far so good. Peers on the PCI bus running 196 * Linux is a common design in telecom systems. The problem is that instead 197 * of all the devices being controlled by a single host, different 198 * devices are controlled by different NPUs on the same bus, leading to 199 * multiple hosts on the bus. The exact bus layout looks like: 200 * 201 * Bus 0 202 * Master NPU <-------------------+-------------------> Slave NPU 203 * | 204 * | 205 * P2P 206 * | 207 * 208 * Bus 1 | 209 * <--+------+---------+---------+------+--> 210 * | | | | | 211 * | | | | | 212 * ... Dev PMC Media Eth0 Eth1 ... 213 * 214 * The master controls all but Eth1, which is controlled by the 215 * slave. What this means is that the both the master and the slave 216 * have to scan the bus, but only one of them can enumerate the bus. 217 * In addition, after the bus is scanned, each kernel must remove 218 * the device(s) it does not control from the PCI dev list otherwise 219 * a driver on each NPU will try to manage it and we will have horrible 220 * conflicts. Oh..and the slave NPU needs to see the master NPU 221 * for Intel's drivers to work properly. Closed source drivers... 222 * 223 * The way we deal with this is fairly simple but ugly: 224 * 225 * 1) Let master scan and enumerate the bus completely. 226 * 2) Master deletes Eth1 from device list. 227 * 3) Slave scans bus and then deletes all but Eth1 (Eth0 on slave) 228 * from device list. 229 * 4) Find HW designers and LART them. 230 * 231 * The boards also do not do normal PCI IRQ routing, or any sort of 232 * sensical swizzling, so we just need to check where on the bus a 233 * device sits and figure out to which CPLD pin the interrupt is routed. 234 * See ixdp2[48]00.c files. 235 * 236 *************************************************************************/ 237void ixdp2x00_slave_pci_postinit(void) 238{ 239 struct pci_dev *dev; 240 241 /* 242 * Remove PMC device is there is one 243 */ 244 if((dev = pci_get_bus_and_slot(1, IXDP2X00_PMC_DEVFN))) { 245 pci_remove_bus_device(dev); 246 pci_dev_put(dev); 247 } 248 249 dev = pci_get_bus_and_slot(0, IXDP2X00_21555_DEVFN); 250 pci_remove_bus_device(dev); 251 pci_dev_put(dev); 252} 253 254/************************************************************************** 255 * IXDP2x00 Machine Setup 256 *************************************************************************/ 257static struct flash_platform_data ixdp2x00_platform_data = { 258 .map_name = "cfi_probe", 259 .width = 1, 260}; 261 262static struct ixp2000_flash_data ixdp2x00_flash_data = { 263 .platform_data = &ixdp2x00_platform_data, 264 .nr_banks = 1 265}; 266 267static struct resource ixdp2x00_flash_resource = { 268 .start = 0xc4000000, 269 .end = 0xc4000000 + 0x00ffffff, 270 .flags = IORESOURCE_MEM, 271}; 272 273static struct platform_device ixdp2x00_flash = { 274 .name = "IXP2000-Flash", 275 .id = 0, 276 .dev = { 277 .platform_data = &ixdp2x00_flash_data, 278 }, 279 .num_resources = 1, 280 .resource = &ixdp2x00_flash_resource, 281}; 282 283static struct ixp2000_i2c_pins ixdp2x00_i2c_gpio_pins = { 284 .sda_pin = IXDP2X00_GPIO_SDA, 285 .scl_pin = IXDP2X00_GPIO_SCL, 286}; 287 288static struct platform_device ixdp2x00_i2c_controller = { 289 .name = "IXP2000-I2C", 290 .id = 0, 291 .dev = { 292 .platform_data = &ixdp2x00_i2c_gpio_pins, 293 }, 294 .num_resources = 0 295}; 296 297static struct platform_device *ixdp2x00_devices[] __initdata = { 298 &ixdp2x00_flash, 299 &ixdp2x00_i2c_controller 300}; 301 302void __init ixdp2x00_init_machine(void) 303{ 304 gpio_line_set(IXDP2X00_GPIO_I2C_ENABLE, 1); 305 gpio_line_config(IXDP2X00_GPIO_I2C_ENABLE, GPIO_OUT); 306 307 platform_add_devices(ixdp2x00_devices, ARRAY_SIZE(ixdp2x00_devices)); 308 ixp2000_uart_init(); 309} 310