1/* 2 * arch/arm/mach-ixp23xx/core.c 3 * 4 * Core routines for IXP23xx chips 5 * 6 * Author: Deepak Saxena <dsaxena@plexity.net> 7 * 8 * Copyright 2005 (c) MontaVista Software, Inc. 9 * 10 * Based on 2.4 code Copyright 2004 (c) Intel Corporation 11 * 12 * This file is licensed under the terms of the GNU General Public 13 * License version 2. This program is licensed "as is" without any 14 * warranty of any kind, whether express or implied. 15 */ 16 17#include <linux/kernel.h> 18#include <linux/init.h> 19#include <linux/spinlock.h> 20#include <linux/sched.h> 21#include <linux/interrupt.h> 22#include <linux/serial.h> 23#include <linux/tty.h> 24#include <linux/bitops.h> 25#include <linux/serial_8250.h> 26#include <linux/serial_core.h> 27#include <linux/device.h> 28#include <linux/mm.h> 29#include <linux/time.h> 30#include <linux/timex.h> 31 32#include <asm/types.h> 33#include <asm/setup.h> 34#include <asm/memory.h> 35#include <mach/hardware.h> 36#include <asm/irq.h> 37#include <asm/system.h> 38#include <asm/tlbflush.h> 39#include <asm/pgtable.h> 40 41#include <asm/mach/map.h> 42#include <asm/mach/time.h> 43#include <asm/mach/irq.h> 44#include <asm/mach/arch.h> 45 46 47/************************************************************************* 48 * Chip specific mappings shared by all IXP23xx systems 49 *************************************************************************/ 50static struct map_desc ixp23xx_io_desc[] __initdata = { 51 { /* XSI-CPP CSRs */ 52 .virtual = IXP23XX_XSI2CPP_CSR_VIRT, 53 .pfn = __phys_to_pfn(IXP23XX_XSI2CPP_CSR_PHYS), 54 .length = IXP23XX_XSI2CPP_CSR_SIZE, 55 .type = MT_DEVICE, 56 }, { /* Expansion Bus Config */ 57 .virtual = IXP23XX_EXP_CFG_VIRT, 58 .pfn = __phys_to_pfn(IXP23XX_EXP_CFG_PHYS), 59 .length = IXP23XX_EXP_CFG_SIZE, 60 .type = MT_DEVICE, 61 }, { /* UART, Interrupt ctrl, GPIO, timers, NPEs, MACS,.... */ 62 .virtual = IXP23XX_PERIPHERAL_VIRT, 63 .pfn = __phys_to_pfn(IXP23XX_PERIPHERAL_PHYS), 64 .length = IXP23XX_PERIPHERAL_SIZE, 65 .type = MT_DEVICE, 66 }, { /* CAP CSRs */ 67 .virtual = IXP23XX_CAP_CSR_VIRT, 68 .pfn = __phys_to_pfn(IXP23XX_CAP_CSR_PHYS), 69 .length = IXP23XX_CAP_CSR_SIZE, 70 .type = MT_DEVICE, 71 }, { /* MSF CSRs */ 72 .virtual = IXP23XX_MSF_CSR_VIRT, 73 .pfn = __phys_to_pfn(IXP23XX_MSF_CSR_PHYS), 74 .length = IXP23XX_MSF_CSR_SIZE, 75 .type = MT_DEVICE, 76 }, { /* PCI I/O Space */ 77 .virtual = IXP23XX_PCI_IO_VIRT, 78 .pfn = __phys_to_pfn(IXP23XX_PCI_IO_PHYS), 79 .length = IXP23XX_PCI_IO_SIZE, 80 .type = MT_DEVICE, 81 }, { /* PCI Config Space */ 82 .virtual = IXP23XX_PCI_CFG_VIRT, 83 .pfn = __phys_to_pfn(IXP23XX_PCI_CFG_PHYS), 84 .length = IXP23XX_PCI_CFG_SIZE, 85 .type = MT_DEVICE, 86 }, { /* PCI local CFG CSRs */ 87 .virtual = IXP23XX_PCI_CREG_VIRT, 88 .pfn = __phys_to_pfn(IXP23XX_PCI_CREG_PHYS), 89 .length = IXP23XX_PCI_CREG_SIZE, 90 .type = MT_DEVICE, 91 }, { /* PCI MEM Space */ 92 .virtual = IXP23XX_PCI_MEM_VIRT, 93 .pfn = __phys_to_pfn(IXP23XX_PCI_MEM_PHYS), 94 .length = IXP23XX_PCI_MEM_SIZE, 95 .type = MT_DEVICE, 96 } 97}; 98 99void __init ixp23xx_map_io(void) 100{ 101 iotable_init(ixp23xx_io_desc, ARRAY_SIZE(ixp23xx_io_desc)); 102} 103 104 105/*************************************************************************** 106 * IXP23xx Interrupt Handling 107 ***************************************************************************/ 108enum ixp23xx_irq_type { 109 IXP23XX_IRQ_LEVEL, IXP23XX_IRQ_EDGE 110}; 111 112static void ixp23xx_config_irq(unsigned int, enum ixp23xx_irq_type); 113 114static int ixp23xx_irq_set_type(unsigned int irq, unsigned int type) 115{ 116 int line = irq - IRQ_IXP23XX_GPIO6 + 6; 117 u32 int_style; 118 enum ixp23xx_irq_type irq_type; 119 volatile u32 *int_reg; 120 121 /* 122 * Only GPIOs 6-15 are wired to interrupts on IXP23xx 123 */ 124 if (line < 6 || line > 15) 125 return -EINVAL; 126 127 switch (type) { 128 case IRQ_TYPE_EDGE_BOTH: 129 int_style = IXP23XX_GPIO_STYLE_TRANSITIONAL; 130 irq_type = IXP23XX_IRQ_EDGE; 131 break; 132 case IRQ_TYPE_EDGE_RISING: 133 int_style = IXP23XX_GPIO_STYLE_RISING_EDGE; 134 irq_type = IXP23XX_IRQ_EDGE; 135 break; 136 case IRQ_TYPE_EDGE_FALLING: 137 int_style = IXP23XX_GPIO_STYLE_FALLING_EDGE; 138 irq_type = IXP23XX_IRQ_EDGE; 139 break; 140 case IRQ_TYPE_LEVEL_HIGH: 141 int_style = IXP23XX_GPIO_STYLE_ACTIVE_HIGH; 142 irq_type = IXP23XX_IRQ_LEVEL; 143 break; 144 case IRQ_TYPE_LEVEL_LOW: 145 int_style = IXP23XX_GPIO_STYLE_ACTIVE_LOW; 146 irq_type = IXP23XX_IRQ_LEVEL; 147 break; 148 default: 149 return -EINVAL; 150 } 151 152 ixp23xx_config_irq(irq, irq_type); 153 154 if (line >= 8) { /* pins 8-15 */ 155 line -= 8; 156 int_reg = (volatile u32 *)IXP23XX_GPIO_GPIT2R; 157 } else { /* pins 0-7 */ 158 int_reg = (volatile u32 *)IXP23XX_GPIO_GPIT1R; 159 } 160 161 /* 162 * Clear pending interrupts 163 */ 164 *IXP23XX_GPIO_GPISR = (1 << line); 165 166 /* Clear the style for the appropriate pin */ 167 *int_reg &= ~(IXP23XX_GPIO_STYLE_MASK << 168 (line * IXP23XX_GPIO_STYLE_SIZE)); 169 170 /* Set the new style */ 171 *int_reg |= (int_style << (line * IXP23XX_GPIO_STYLE_SIZE)); 172 173 return 0; 174} 175 176static void ixp23xx_irq_mask(unsigned int irq) 177{ 178 volatile unsigned long *intr_reg; 179 180 if (irq >= 56) 181 irq += 8; 182 183 intr_reg = IXP23XX_INTR_EN1 + (irq / 32); 184 *intr_reg &= ~(1 << (irq % 32)); 185} 186 187static void ixp23xx_irq_ack(unsigned int irq) 188{ 189 int line = irq - IRQ_IXP23XX_GPIO6 + 6; 190 191 if ((line < 6) || (line > 15)) 192 return; 193 194 *IXP23XX_GPIO_GPISR = (1 << line); 195} 196 197/* 198 * Level triggered interrupts on GPIO lines can only be cleared when the 199 * interrupt condition disappears. 200 */ 201static void ixp23xx_irq_level_unmask(unsigned int irq) 202{ 203 volatile unsigned long *intr_reg; 204 205 ixp23xx_irq_ack(irq); 206 207 if (irq >= 56) 208 irq += 8; 209 210 intr_reg = IXP23XX_INTR_EN1 + (irq / 32); 211 *intr_reg |= (1 << (irq % 32)); 212} 213 214static void ixp23xx_irq_edge_unmask(unsigned int irq) 215{ 216 volatile unsigned long *intr_reg; 217 218 if (irq >= 56) 219 irq += 8; 220 221 intr_reg = IXP23XX_INTR_EN1 + (irq / 32); 222 *intr_reg |= (1 << (irq % 32)); 223} 224 225static struct irq_chip ixp23xx_irq_level_chip = { 226 .ack = ixp23xx_irq_mask, 227 .mask = ixp23xx_irq_mask, 228 .unmask = ixp23xx_irq_level_unmask, 229 .set_type = ixp23xx_irq_set_type 230}; 231 232static struct irq_chip ixp23xx_irq_edge_chip = { 233 .ack = ixp23xx_irq_ack, 234 .mask = ixp23xx_irq_mask, 235 .unmask = ixp23xx_irq_edge_unmask, 236 .set_type = ixp23xx_irq_set_type 237}; 238 239static void ixp23xx_pci_irq_mask(unsigned int irq) 240{ 241 *IXP23XX_PCI_XSCALE_INT_ENABLE &= ~(1 << (IRQ_IXP23XX_INTA + 27 - irq)); 242} 243 244static void ixp23xx_pci_irq_unmask(unsigned int irq) 245{ 246 *IXP23XX_PCI_XSCALE_INT_ENABLE |= (1 << (IRQ_IXP23XX_INTA + 27 - irq)); 247} 248 249/* 250 * TODO: Should this just be done at ASM level? 251 */ 252static void pci_handler(unsigned int irq, struct irq_desc *desc) 253{ 254 u32 pci_interrupt; 255 unsigned int irqno; 256 257 pci_interrupt = *IXP23XX_PCI_XSCALE_INT_STATUS; 258 259 desc->chip->ack(irq); 260 261 /* See which PCI_INTA, or PCI_INTB interrupted */ 262 if (pci_interrupt & (1 << 26)) { 263 irqno = IRQ_IXP23XX_INTB; 264 } else if (pci_interrupt & (1 << 27)) { 265 irqno = IRQ_IXP23XX_INTA; 266 } else { 267 BUG(); 268 } 269 270 generic_handle_irq(irqno); 271 272 desc->chip->unmask(irq); 273} 274 275static struct irq_chip ixp23xx_pci_irq_chip = { 276 .ack = ixp23xx_pci_irq_mask, 277 .mask = ixp23xx_pci_irq_mask, 278 .unmask = ixp23xx_pci_irq_unmask 279}; 280 281static void ixp23xx_config_irq(unsigned int irq, enum ixp23xx_irq_type type) 282{ 283 switch (type) { 284 case IXP23XX_IRQ_LEVEL: 285 set_irq_chip(irq, &ixp23xx_irq_level_chip); 286 set_irq_handler(irq, handle_level_irq); 287 break; 288 case IXP23XX_IRQ_EDGE: 289 set_irq_chip(irq, &ixp23xx_irq_edge_chip); 290 set_irq_handler(irq, handle_edge_irq); 291 break; 292 } 293 set_irq_flags(irq, IRQF_VALID); 294} 295 296void __init ixp23xx_init_irq(void) 297{ 298 int irq; 299 300 /* Route everything to IRQ */ 301 *IXP23XX_INTR_SEL1 = 0x0; 302 *IXP23XX_INTR_SEL2 = 0x0; 303 *IXP23XX_INTR_SEL3 = 0x0; 304 *IXP23XX_INTR_SEL4 = 0x0; 305 306 /* Mask all sources */ 307 *IXP23XX_INTR_EN1 = 0x0; 308 *IXP23XX_INTR_EN2 = 0x0; 309 *IXP23XX_INTR_EN3 = 0x0; 310 *IXP23XX_INTR_EN4 = 0x0; 311 312 /* 313 * Configure all IRQs for level-sensitive operation 314 */ 315 for (irq = 0; irq <= NUM_IXP23XX_RAW_IRQS; irq++) { 316 ixp23xx_config_irq(irq, IXP23XX_IRQ_LEVEL); 317 } 318 319 for (irq = IRQ_IXP23XX_INTA; irq <= IRQ_IXP23XX_INTB; irq++) { 320 set_irq_chip(irq, &ixp23xx_pci_irq_chip); 321 set_irq_handler(irq, handle_level_irq); 322 set_irq_flags(irq, IRQF_VALID); 323 } 324 325 set_irq_chained_handler(IRQ_IXP23XX_PCI_INT_RPH, pci_handler); 326} 327 328 329/************************************************************************* 330 * Timer-tick functions for IXP23xx 331 *************************************************************************/ 332#define CLOCK_TICKS_PER_USEC (CLOCK_TICK_RATE / USEC_PER_SEC) 333 334static unsigned long next_jiffy_time; 335 336static unsigned long 337ixp23xx_gettimeoffset(void) 338{ 339 unsigned long elapsed; 340 341 elapsed = *IXP23XX_TIMER_CONT - (next_jiffy_time - LATCH); 342 343 return elapsed / CLOCK_TICKS_PER_USEC; 344} 345 346static irqreturn_t 347ixp23xx_timer_interrupt(int irq, void *dev_id) 348{ 349 /* Clear Pending Interrupt by writing '1' to it */ 350 *IXP23XX_TIMER_STATUS = IXP23XX_TIMER1_INT_PEND; 351 while ((signed long)(*IXP23XX_TIMER_CONT - next_jiffy_time) >= LATCH) { 352 timer_tick(); 353 next_jiffy_time += LATCH; 354 } 355 356 return IRQ_HANDLED; 357} 358 359static struct irqaction ixp23xx_timer_irq = { 360 .name = "IXP23xx Timer Tick", 361 .handler = ixp23xx_timer_interrupt, 362 .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, 363}; 364 365void __init ixp23xx_init_timer(void) 366{ 367 /* Clear Pending Interrupt by writing '1' to it */ 368 *IXP23XX_TIMER_STATUS = IXP23XX_TIMER1_INT_PEND; 369 370 /* Setup the Timer counter value */ 371 *IXP23XX_TIMER1_RELOAD = 372 (LATCH & ~IXP23XX_TIMER_RELOAD_MASK) | IXP23XX_TIMER_ENABLE; 373 374 *IXP23XX_TIMER_CONT = 0; 375 next_jiffy_time = LATCH; 376 377 /* Connect the interrupt handler and enable the interrupt */ 378 setup_irq(IRQ_IXP23XX_TIMER1, &ixp23xx_timer_irq); 379} 380 381struct sys_timer ixp23xx_timer = { 382 .init = ixp23xx_init_timer, 383 .offset = ixp23xx_gettimeoffset, 384}; 385 386 387/************************************************************************* 388 * IXP23xx Platform Initialization 389 *************************************************************************/ 390static struct resource ixp23xx_uart_resources[] = { 391 { 392 .start = IXP23XX_UART1_PHYS, 393 .end = IXP23XX_UART1_PHYS + 0x0fff, 394 .flags = IORESOURCE_MEM 395 }, { 396 .start = IXP23XX_UART2_PHYS, 397 .end = IXP23XX_UART2_PHYS + 0x0fff, 398 .flags = IORESOURCE_MEM 399 } 400}; 401 402static struct plat_serial8250_port ixp23xx_uart_data[] = { 403 { 404 .mapbase = IXP23XX_UART1_PHYS, 405 .membase = (char *)(IXP23XX_UART1_VIRT + 3), 406 .irq = IRQ_IXP23XX_UART1, 407 .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST, 408 .iotype = UPIO_MEM, 409 .regshift = 2, 410 .uartclk = IXP23XX_UART_XTAL, 411 }, { 412 .mapbase = IXP23XX_UART2_PHYS, 413 .membase = (char *)(IXP23XX_UART2_VIRT + 3), 414 .irq = IRQ_IXP23XX_UART2, 415 .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST, 416 .iotype = UPIO_MEM, 417 .regshift = 2, 418 .uartclk = IXP23XX_UART_XTAL, 419 }, 420 { }, 421}; 422 423static struct platform_device ixp23xx_uart = { 424 .name = "serial8250", 425 .id = 0, 426 .dev.platform_data = ixp23xx_uart_data, 427 .num_resources = 2, 428 .resource = ixp23xx_uart_resources, 429}; 430 431static struct platform_device *ixp23xx_devices[] __initdata = { 432 &ixp23xx_uart, 433}; 434 435void __init ixp23xx_sys_init(void) 436{ 437 *IXP23XX_EXP_UNIT_FUSE |= 0xf; 438 platform_add_devices(ixp23xx_devices, ARRAY_SIZE(ixp23xx_devices)); 439} 440