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 write_seqlock(&xtime_lock); 182 183 /* latch and read timer 1 */ 184 __raw_writeb(0x40, PIT_CTRL); 185 count = __raw_readb(PIT_T1); 186 count |= __raw_readb(PIT_T1) << 8; 187 188 count += COUNT; 189 190 __raw_writeb(count & 0xff, PIT_T1); 191 __raw_writeb(count >> 8, PIT_T1); 192 193 timer_tick(); 194 195 write_sequnlock(&xtime_lock); 196 197 return IRQ_HANDLED; 198} 199 200static struct irqaction ebsa110_timer_irq = { 201 .name = "EBSA110 Timer Tick", 202 .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, 203 .handler = ebsa110_timer_interrupt, 204}; 205 206/* 207 * Set up timer interrupt. 208 */ 209static void __init ebsa110_timer_init(void) 210{ 211 /* 212 * Timer 1, mode 2, LSB/MSB 213 */ 214 __raw_writeb(0x70, PIT_CTRL); 215 __raw_writeb(COUNT & 0xff, PIT_T1); 216 __raw_writeb(COUNT >> 8, PIT_T1); 217 218 setup_irq(IRQ_EBSA110_TIMER0, &ebsa110_timer_irq); 219} 220 221static struct sys_timer ebsa110_timer = { 222 .init = ebsa110_timer_init, 223 .offset = ebsa110_gettimeoffset, 224}; 225 226static struct plat_serial8250_port serial_platform_data[] = { 227 { 228 .iobase = 0x3f8, 229 .irq = 1, 230 .uartclk = 1843200, 231 .regshift = 0, 232 .iotype = UPIO_PORT, 233 .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST, 234 }, 235 { 236 .iobase = 0x2f8, 237 .irq = 2, 238 .uartclk = 1843200, 239 .regshift = 0, 240 .iotype = UPIO_PORT, 241 .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST, 242 }, 243 { }, 244}; 245 246static struct platform_device serial_device = { 247 .name = "serial8250", 248 .id = PLAT8250_DEV_PLATFORM, 249 .dev = { 250 .platform_data = serial_platform_data, 251 }, 252}; 253 254static struct resource am79c961_resources[] = { 255 { 256 .start = 0x220, 257 .end = 0x238, 258 .flags = IORESOURCE_IO, 259 }, { 260 .start = IRQ_EBSA110_ETHERNET, 261 .end = IRQ_EBSA110_ETHERNET, 262 .flags = IORESOURCE_IRQ, 263 }, 264}; 265 266static struct platform_device am79c961_device = { 267 .name = "am79c961", 268 .id = -1, 269 .num_resources = ARRAY_SIZE(am79c961_resources), 270 .resource = am79c961_resources, 271}; 272 273static struct platform_device *ebsa110_devices[] = { 274 &serial_device, 275 &am79c961_device, 276}; 277 278static int __init ebsa110_init(void) 279{ 280 return platform_add_devices(ebsa110_devices, ARRAY_SIZE(ebsa110_devices)); 281} 282 283arch_initcall(ebsa110_init); 284 285MACHINE_START(EBSA110, "EBSA110") 286 /* Maintainer: Russell King */ 287 .phys_io = 0xe0000000, 288 .io_pg_offst = ((0xe0000000) >> 18) & 0xfffc, 289 .boot_params = 0x00000400, 290 .reserve_lp0 = 1, 291 .reserve_lp2 = 1, 292 .soft_reboot = 1, 293 .map_io = ebsa110_map_io, 294 .init_irq = ebsa110_init_irq, 295 .timer = &ebsa110_timer, 296MACHINE_END 297