core.c revision 6df29debb7fc04ac3f92038c57437f40bab4e72d
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 irqchip 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, do_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, TRICK4_PHYS, PGDIR_SIZE, MT_DEVICE }, /* IRQ_STAT/IRQ_MCLR */ 80 { IRQ_MASK, TRICK3_PHYS, PGDIR_SIZE, MT_DEVICE }, /* IRQ_MASK/IRQ_MSET */ 81 { SOFT_BASE, TRICK1_PHYS, PGDIR_SIZE, MT_DEVICE }, /* SOFT_BASE */ 82 { PIT_BASE, TRICK0_PHYS, PGDIR_SIZE, MT_DEVICE }, /* PIT_BASE */ 83 84 /* 85 * self-decode ISAIO space 86 */ 87 { ISAIO_BASE, ISAIO_PHYS, ISAIO_SIZE, MT_DEVICE }, 88 { ISAMEM_BASE, ISAMEM_PHYS, ISAMEM_SIZE, MT_DEVICE } 89}; 90 91static void __init ebsa110_map_io(void) 92{ 93 iotable_init(ebsa110_io_desc, ARRAY_SIZE(ebsa110_io_desc)); 94} 95 96 97#define PIT_CTRL (PIT_BASE + 0x0d) 98#define PIT_T2 (PIT_BASE + 0x09) 99#define PIT_T1 (PIT_BASE + 0x05) 100#define PIT_T0 (PIT_BASE + 0x01) 101 102/* 103 * This is the rate at which your MCLK signal toggles (in Hz) 104 * This was measured on a 10 digit frequency counter sampling 105 * over 1 second. 106 */ 107#define MCLK 47894000 108 109/* 110 * This is the rate at which the PIT timers get clocked 111 */ 112#define CLKBY7 (MCLK / 7) 113 114/* 115 * This is the counter value. We tick at 200Hz on this platform. 116 */ 117#define COUNT ((CLKBY7 + (HZ / 2)) / HZ) 118 119/* 120 * Get the time offset from the system PIT. Note that if we have missed an 121 * interrupt, then the PIT counter will roll over (ie, be negative). 122 * This actually works out to be convenient. 123 */ 124static unsigned long ebsa110_gettimeoffset(void) 125{ 126 unsigned long offset, count; 127 128 __raw_writeb(0x40, PIT_CTRL); 129 count = __raw_readb(PIT_T1); 130 count |= __raw_readb(PIT_T1) << 8; 131 132 /* 133 * If count > COUNT, make the number negative. 134 */ 135 if (count > COUNT) 136 count |= 0xffff0000; 137 138 offset = COUNT; 139 offset -= count; 140 141 /* 142 * `offset' is in units of timer counts. Convert 143 * offset to units of microseconds. 144 */ 145 offset = offset * (1000000 / HZ) / COUNT; 146 147 return offset; 148} 149 150static irqreturn_t 151ebsa110_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) 152{ 153 u32 count; 154 155 write_seqlock(&xtime_lock); 156 157 /* latch and read timer 1 */ 158 __raw_writeb(0x40, PIT_CTRL); 159 count = __raw_readb(PIT_T1); 160 count |= __raw_readb(PIT_T1) << 8; 161 162 count += COUNT; 163 164 __raw_writeb(count & 0xff, PIT_T1); 165 __raw_writeb(count >> 8, PIT_T1); 166 167 timer_tick(regs); 168 169 write_sequnlock(&xtime_lock); 170 171 return IRQ_HANDLED; 172} 173 174static struct irqaction ebsa110_timer_irq = { 175 .name = "EBSA110 Timer Tick", 176 .flags = SA_INTERRUPT | SA_TIMER, 177 .handler = ebsa110_timer_interrupt, 178}; 179 180/* 181 * Set up timer interrupt. 182 */ 183static void __init ebsa110_timer_init(void) 184{ 185 /* 186 * Timer 1, mode 2, LSB/MSB 187 */ 188 __raw_writeb(0x70, PIT_CTRL); 189 __raw_writeb(COUNT & 0xff, PIT_T1); 190 __raw_writeb(COUNT >> 8, PIT_T1); 191 192 setup_irq(IRQ_EBSA110_TIMER0, &ebsa110_timer_irq); 193} 194 195static struct sys_timer ebsa110_timer = { 196 .init = ebsa110_timer_init, 197 .offset = ebsa110_gettimeoffset, 198}; 199 200static struct plat_serial8250_port serial_platform_data[] = { 201 { 202 .iobase = 0x3f8, 203 .irq = 1, 204 .uartclk = 1843200, 205 .regshift = 0, 206 .iotype = UPIO_PORT, 207 .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST, 208 }, 209 { 210 .iobase = 0x2f8, 211 .irq = 2, 212 .uartclk = 1843200, 213 .regshift = 0, 214 .iotype = UPIO_PORT, 215 .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST, 216 }, 217 { }, 218}; 219 220static struct platform_device serial_device = { 221 .name = "serial8250", 222 .id = PLAT8250_DEV_PLATFORM, 223 .dev = { 224 .platform_data = serial_platform_data, 225 }, 226}; 227 228static int __init ebsa110_init(void) 229{ 230 return platform_device_register(&serial_device); 231} 232 233arch_initcall(ebsa110_init); 234 235MACHINE_START(EBSA110, "EBSA110") 236 /* Maintainer: Russell King */ 237 .phys_ram = 0x00000000, 238 .phys_io = 0xe0000000, 239 .io_pg_offst = ((0xe0000000) >> 18) & 0xfffc, 240 .boot_params = 0x00000400, 241 .reserve_lp0 = 1, 242 .reserve_lp2 = 1, 243 .soft_reboot = 1, 244 .map_io = ebsa110_map_io, 245 .init_irq = ebsa110_init_irq, 246 .timer = &ebsa110_timer, 247MACHINE_END 248