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
  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,
 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                     = 0,
 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        BOOT_MEM(0x00000000, 0xe0000000, 0xe0000000)
 238        BOOT_PARAMS(0x00000400)
 239        DISABLE_PARPORT(0)
 240        DISABLE_PARPORT(2)
 241        SOFT_REBOOT
 242        MAPIO(ebsa110_map_io)
 243        INITIRQ(ebsa110_init_irq)
 244        .timer          = &ebsa110_timer,
 245MACHINE_END
 246
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.