core.c revision 193c3cc12583344be01206078d9ad3fec5dbc397
1/* 2 * linux/arch/arm/mach-ebsa110/core.c 3 * 4 * Copyright (C) 1998-2001 Russell King 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 2 as 8 * published by the Free Software Foundation. 9 * 10 * Extra MM routines for the EBSA-110 architecture 11 */ 12#include <linux/kernel.h> 13#include <linux/mm.h> 14#include <linux/interrupt.h> 15#include <linux/serial_8250.h> 16#include <linux/init.h> 17 18#include <asm/hardware.h> 19#include <asm/irq.h> 20#include <asm/io.h> 21#include <asm/setup.h> 22#include <asm/mach-types.h> 23#include <asm/pgtable.h> 24#include <asm/page.h> 25#include <asm/system.h> 26 27#include <asm/mach/arch.h> 28#include <asm/mach/irq.h> 29#include <asm/mach/map.h> 30 31#include <asm/mach/time.h> 32 33#define IRQ_MASK 0xfe000000 /* read */ 34#define IRQ_MSET 0xfe000000 /* write */ 35#define IRQ_STAT 0xff000000 /* read */ 36#define IRQ_MCLR 0xff000000 /* write */ 37 38static void ebsa110_mask_irq(unsigned int irq) 39{ 40 __raw_writeb(1 << irq, IRQ_MCLR); 41} 42 43static void ebsa110_unmask_irq(unsigned int irq) 44{ 45 __raw_writeb(1 << irq, IRQ_MSET); 46} 47 48static struct irq_chip ebsa110_irq_chip = { 49 .ack = ebsa110_mask_irq, 50 .mask = ebsa110_mask_irq, 51 .unmask = ebsa110_unmask_irq, 52}; 53 54static void __init ebsa110_init_irq(void) 55{ 56 unsigned long flags; 57 unsigned int irq; 58 59 local_irq_save(flags); 60 __raw_writeb(0xff, IRQ_MCLR); 61 __raw_writeb(0x55, IRQ_MSET); 62 __raw_writeb(0x00, IRQ_MSET); 63 if (__raw_readb(IRQ_MASK) != 0x55) 64 while (1); 65 __raw_writeb(0xff, IRQ_MCLR); /* clear all interrupt enables */ 66 local_irq_restore(flags); 67 68 for (irq = 0; irq < NR_IRQS; irq++) { 69 set_irq_chip(irq, &ebsa110_irq_chip); 70 set_irq_handler(irq, handle_level_irq); 71 set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); 72 } 73} 74 75static struct map_desc ebsa110_io_desc[] __initdata = { 76 /* 77 * sparse external-decode ISAIO space 78 */ 79 { /* IRQ_STAT/IRQ_MCLR */ 80 .virtual = IRQ_STAT, 81 .pfn = __phys_to_pfn(TRICK4_PHYS), 82 .length = PGDIR_SIZE, 83 .type = MT_DEVICE 84 }, { /* IRQ_MASK/IRQ_MSET */ 85 .virtual = IRQ_MASK, 86 .pfn = __phys_to_pfn(TRICK3_PHYS), 87 .length = PGDIR_SIZE, 88 .type = MT_DEVICE 89 }, { /* SOFT_BASE */ 90 .virtual = SOFT_BASE, 91 .pfn = __phys_to_pfn(TRICK1_PHYS), 92 .length = PGDIR_SIZE, 93 .type = MT_DEVICE 94 }, { /* PIT_BASE */ 95 .virtual = PIT_BASE, 96 .pfn = __phys_to_pfn(TRICK0_PHYS), 97 .length = PGDIR_SIZE, 98 .type = MT_DEVICE 99 }, 100 101 /* 102 * self-decode ISAIO space 103 */ 104 { 105 .virtual = ISAIO_BASE, 106 .pfn = __phys_to_pfn(ISAIO_PHYS), 107 .length = ISAIO_SIZE, 108 .type = MT_DEVICE 109 }, { 110 .virtual = ISAMEM_BASE, 111 .pfn = __phys_to_pfn(ISAMEM_PHYS), 112 .length = ISAMEM_SIZE, 113 .type = MT_DEVICE 114 } 115}; 116 117static void __init ebsa110_map_io(void) 118{ 119 iotable_init(ebsa110_io_desc, ARRAY_SIZE(ebsa110_io_desc)); 120} 121 122 123#define PIT_CTRL (PIT_BASE + 0x0d) 124#define PIT_T2 (PIT_BASE + 0x09) 125#define PIT_T1 (PIT_BASE + 0x05) 126#define PIT_T0 (PIT_BASE + 0x01) 127 128/* 129 * This is the rate at which your MCLK signal toggles (in Hz) 130 * This was measured on a 10 digit frequency counter sampling 131 * over 1 second. 132 */ 133#define MCLK 47894000 134 135/* 136 * This is the rate at which the PIT timers get clocked 137 */ 138#define CLKBY7 (MCLK / 7) 139 140/* 141 * This is the counter value. We tick at 200Hz on this platform. 142 */ 143#define COUNT ((CLKBY7 + (HZ / 2)) / HZ) 144 145/* 146 * Get the time offset from the system PIT. Note that if we have missed an 147 * interrupt, then the PIT counter will roll over (ie, be negative). 148 * This actually works out to be convenient. 149 */ 150static unsigned long ebsa110_gettimeoffset(void) 151{ 152 unsigned long offset, count; 153 154 __raw_writeb(0x40, PIT_CTRL); 155 count = __raw_readb(PIT_T1); 156 count |= __raw_readb(PIT_T1) << 8; 157 158 /* 159 * If count > COUNT, make the number negative. 160 */ 161 if (count > COUNT) 162 count |= 0xffff0000; 163 164 offset = COUNT; 165 offset -= count; 166 167 /* 168 * `offset' is in units of timer counts. Convert 169 * offset to units of microseconds. 170 */ 171 offset = offset * (1000000 / HZ) / COUNT; 172 173 return offset; 174} 175 176static irqreturn_t 177ebsa110_timer_interrupt(int irq, void *dev_id) 178{ 179 u32 count; 180 181 /* latch and read timer 1 */ 182 __raw_writeb(0x40, PIT_CTRL); 183 count = __raw_readb(PIT_T1); 184 count |= __raw_readb(PIT_T1) << 8; 185 186 count += COUNT; 187 188 __raw_writeb(count & 0xff, PIT_T1); 189 __raw_writeb(count >> 8, PIT_T1); 190 191 timer_tick(); 192 193 return IRQ_HANDLED; 194} 195 196static struct irqaction ebsa110_timer_irq = { 197 .name = "EBSA110 Timer Tick", 198 .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, 199 .handler = ebsa110_timer_interrupt, 200}; 201 202/* 203 * Set up timer interrupt. 204 */ 205static void __init ebsa110_timer_init(void) 206{ 207 /* 208 * Timer 1, mode 2, LSB/MSB 209 */ 210 __raw_writeb(0x70, PIT_CTRL); 211 __raw_writeb(COUNT & 0xff, PIT_T1); 212 __raw_writeb(COUNT >> 8, PIT_T1); 213 214 setup_irq(IRQ_EBSA110_TIMER0, &ebsa110_timer_irq); 215} 216 217static struct sys_timer ebsa110_timer = { 218 .init = ebsa110_timer_init, 219 .offset = ebsa110_gettimeoffset, 220}; 221 222static struct plat_serial8250_port serial_platform_data[] = { 223 { 224 .iobase = 0x3f8, 225 .irq = 1, 226 .uartclk = 1843200, 227 .regshift = 0, 228 .iotype = UPIO_PORT, 229 .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST, 230 }, 231 { 232 .iobase = 0x2f8, 233 .irq = 2, 234 .uartclk = 1843200, 235 .regshift = 0, 236 .iotype = UPIO_PORT, 237 .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST, 238 }, 239 { }, 240}; 241 242static struct platform_device serial_device = { 243 .name = "serial8250", 244 .id = PLAT8250_DEV_PLATFORM, 245 .dev = { 246 .platform_data = serial_platform_data, 247 }, 248}; 249 250static struct resource am79c961_resources[] = { 251 { 252 .start = 0x220, 253 .end = 0x238, 254 .flags = IORESOURCE_IO, 255 }, { 256 .start = IRQ_EBSA110_ETHERNET, 257 .end = IRQ_EBSA110_ETHERNET, 258 .flags = IORESOURCE_IRQ, 259 }, 260}; 261 262static struct platform_device am79c961_device = { 263 .name = "am79c961", 264 .id = -1, 265 .num_resources = ARRAY_SIZE(am79c961_resources), 266 .resource = am79c961_resources, 267}; 268 269static struct platform_device *ebsa110_devices[] = { 270 &serial_device, 271 &am79c961_device, 272}; 273 274static int __init ebsa110_init(void) 275{ 276 return platform_add_devices(ebsa110_devices, ARRAY_SIZE(ebsa110_devices)); 277} 278 279arch_initcall(ebsa110_init); 280 281MACHINE_START(EBSA110, "EBSA110") 282 /* Maintainer: Russell King */ 283 .phys_io = 0xe0000000, 284 .io_pg_offst = ((0xe0000000) >> 18) & 0xfffc, 285 .boot_params = 0x00000400, 286 .reserve_lp0 = 1, 287 .reserve_lp2 = 1, 288 .soft_reboot = 1, 289 .map_io = ebsa110_map_io, 290 .init_irq = ebsa110_init_irq, 291 .timer = &ebsa110_timer, 292MACHINE_END 293