linux/arch/arm/mach-ebsa110/core.c
<<
>>
Prefs
   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#include <linux/io.h>
  18
  19#include <mach/hardware.h>
  20#include <asm/irq.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