Merge to Fedora kernel-2.6.18-1.2224_FC5 patched with stable patch-2.6.18.1-vs2.0...
[linux-2.6.git] / arch / arm / mach-ebsa110 / core.c
index 5c14e04..70dd12e 100644 (file)
@@ -11,6 +11,8 @@
  */
 #include <linux/kernel.h>
 #include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/serial_8250.h>
 #include <linux/init.h>
 
 #include <asm/hardware.h>
@@ -26,6 +28,8 @@
 #include <asm/mach/irq.h>
 #include <asm/mach/map.h>
 
+#include <asm/mach/time.h>
+
 #define IRQ_MASK               0xfe000000      /* read */
 #define IRQ_MSET               0xfe000000      /* write */
 #define IRQ_STAT               0xff000000      /* read */
@@ -72,16 +76,42 @@ static struct map_desc ebsa110_io_desc[] __initdata = {
        /*
         * sparse external-decode ISAIO space
         */
-       { IRQ_STAT,    TRICK4_PHYS, PGDIR_SIZE,  MT_DEVICE }, /* IRQ_STAT/IRQ_MCLR */
-       { IRQ_MASK,    TRICK3_PHYS, PGDIR_SIZE,  MT_DEVICE }, /* IRQ_MASK/IRQ_MSET */
-       { SOFT_BASE,   TRICK1_PHYS, PGDIR_SIZE,  MT_DEVICE }, /* SOFT_BASE */
-       { PIT_BASE,    TRICK0_PHYS, PGDIR_SIZE,  MT_DEVICE }, /* PIT_BASE */
+       {       /* IRQ_STAT/IRQ_MCLR */
+               .virtual        = IRQ_STAT,
+               .pfn            = __phys_to_pfn(TRICK4_PHYS),
+               .length         = PGDIR_SIZE,
+               .type           = MT_DEVICE
+       }, {    /* IRQ_MASK/IRQ_MSET */
+               .virtual        = IRQ_MASK,
+               .pfn            = __phys_to_pfn(TRICK3_PHYS),
+               .length         = PGDIR_SIZE,
+               .type           = MT_DEVICE
+       }, {    /* SOFT_BASE */
+               .virtual        = SOFT_BASE,
+               .pfn            = __phys_to_pfn(TRICK1_PHYS),
+               .length         = PGDIR_SIZE,
+               .type           = MT_DEVICE
+       }, {    /* PIT_BASE */
+               .virtual        = PIT_BASE,
+               .pfn            = __phys_to_pfn(TRICK0_PHYS),
+               .length         = PGDIR_SIZE,
+               .type           = MT_DEVICE
+       },
 
        /*
         * self-decode ISAIO space
         */
-       { ISAIO_BASE,  ISAIO_PHYS,  ISAIO_SIZE,  MT_DEVICE },
-       { ISAMEM_BASE, ISAMEM_PHYS, ISAMEM_SIZE, MT_DEVICE }
+       {
+               .virtual        = ISAIO_BASE,
+               .pfn            = __phys_to_pfn(ISAIO_PHYS),
+               .length         = ISAIO_SIZE,
+               .type           = MT_DEVICE
+       }, {
+               .virtual        = ISAMEM_BASE,
+               .pfn            = __phys_to_pfn(ISAMEM_PHYS),
+               .length         = ISAMEM_SIZE,
+               .type           = MT_DEVICE
+       }
 };
 
 static void __init ebsa110_map_io(void)
@@ -89,13 +119,178 @@ static void __init ebsa110_map_io(void)
        iotable_init(ebsa110_io_desc, ARRAY_SIZE(ebsa110_io_desc));
 }
 
+
+#define PIT_CTRL               (PIT_BASE + 0x0d)
+#define PIT_T2                 (PIT_BASE + 0x09)
+#define PIT_T1                 (PIT_BASE + 0x05)
+#define PIT_T0                 (PIT_BASE + 0x01)
+
+/*
+ * This is the rate at which your MCLK signal toggles (in Hz)
+ * This was measured on a 10 digit frequency counter sampling
+ * over 1 second.
+ */
+#define MCLK   47894000
+
+/*
+ * This is the rate at which the PIT timers get clocked
+ */
+#define CLKBY7 (MCLK / 7)
+
+/*
+ * This is the counter value.  We tick at 200Hz on this platform.
+ */
+#define COUNT  ((CLKBY7 + (HZ / 2)) / HZ)
+
+/*
+ * Get the time offset from the system PIT.  Note that if we have missed an
+ * interrupt, then the PIT counter will roll over (ie, be negative).
+ * This actually works out to be convenient.
+ */
+static unsigned long ebsa110_gettimeoffset(void)
+{
+       unsigned long offset, count;
+
+       __raw_writeb(0x40, PIT_CTRL);
+       count = __raw_readb(PIT_T1);
+       count |= __raw_readb(PIT_T1) << 8;
+
+       /*
+        * If count > COUNT, make the number negative.
+        */
+       if (count > COUNT)
+               count |= 0xffff0000;
+
+       offset = COUNT;
+       offset -= count;
+
+       /*
+        * `offset' is in units of timer counts.  Convert
+        * offset to units of microseconds.
+        */
+       offset = offset * (1000000 / HZ) / COUNT;
+
+       return offset;
+}
+
+static irqreturn_t
+ebsa110_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+       u32 count;
+
+       write_seqlock(&xtime_lock);
+
+       /* latch and read timer 1 */
+       __raw_writeb(0x40, PIT_CTRL);
+       count = __raw_readb(PIT_T1);
+       count |= __raw_readb(PIT_T1) << 8;
+
+       count += COUNT;
+
+       __raw_writeb(count & 0xff, PIT_T1);
+       __raw_writeb(count >> 8, PIT_T1);
+
+       timer_tick(regs);
+
+       write_sequnlock(&xtime_lock);
+
+       return IRQ_HANDLED;
+}
+
+static struct irqaction ebsa110_timer_irq = {
+       .name           = "EBSA110 Timer Tick",
+       .flags          = IRQF_DISABLED | IRQF_TIMER,
+       .handler        = ebsa110_timer_interrupt,
+};
+
+/*
+ * Set up timer interrupt.
+ */
+static void __init ebsa110_timer_init(void)
+{
+       /*
+        * Timer 1, mode 2, LSB/MSB
+        */
+       __raw_writeb(0x70, PIT_CTRL);
+       __raw_writeb(COUNT & 0xff, PIT_T1);
+       __raw_writeb(COUNT >> 8, PIT_T1);
+
+       setup_irq(IRQ_EBSA110_TIMER0, &ebsa110_timer_irq);
+}
+
+static struct sys_timer ebsa110_timer = {
+       .init           = ebsa110_timer_init,
+       .offset         = ebsa110_gettimeoffset,
+};
+
+static struct plat_serial8250_port serial_platform_data[] = {
+       {
+               .iobase         = 0x3f8,
+               .irq            = 1,
+               .uartclk        = 1843200,
+               .regshift       = 0,
+               .iotype         = UPIO_PORT,
+               .flags          = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
+       },
+       {
+               .iobase         = 0x2f8,
+               .irq            = 2,
+               .uartclk        = 1843200,
+               .regshift       = 0,
+               .iotype         = UPIO_PORT,
+               .flags          = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
+       },
+       { },
+};
+
+static struct platform_device serial_device = {
+       .name                   = "serial8250",
+       .id                     = PLAT8250_DEV_PLATFORM,
+       .dev                    = {
+               .platform_data  = serial_platform_data,
+       },
+};
+
+static struct resource am79c961_resources[] = {
+       {
+               .start          = 0x220,
+               .end            = 0x238,
+               .flags          = IORESOURCE_IO,
+       }, {
+               .start          = IRQ_EBSA110_ETHERNET,
+               .end            = IRQ_EBSA110_ETHERNET,
+               .flags          = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device am79c961_device = {
+       .name                   = "am79c961",
+       .id                     = -1,
+       .num_resources          = ARRAY_SIZE(am79c961_resources),
+       .resource               = am79c961_resources,
+};
+
+static struct platform_device *ebsa110_devices[] = {
+       &serial_device,
+       &am79c961_device,
+};
+
+static int __init ebsa110_init(void)
+{
+       return platform_add_devices(ebsa110_devices, ARRAY_SIZE(ebsa110_devices));
+}
+
+arch_initcall(ebsa110_init);
+
 MACHINE_START(EBSA110, "EBSA110")
-       MAINTAINER("Russell King")
-       BOOT_MEM(0x00000000, 0xe0000000, 0xe0000000)
-       BOOT_PARAMS(0x00000400)
-       DISABLE_PARPORT(0)
-       DISABLE_PARPORT(2)
-       SOFT_REBOOT
-       MAPIO(ebsa110_map_io)
-       INITIRQ(ebsa110_init_irq)
+       /* Maintainer: Russell King */
+       .phys_io        = 0xe0000000,
+       .io_pg_offst    = ((0xe0000000) >> 18) & 0xfffc,
+       .boot_params    = 0x00000400,
+       .reserve_lp0    = 1,
+       .reserve_lp2    = 1,
+       .soft_reboot    = 1,
+       .map_io         = ebsa110_map_io,
+       .init_irq       = ebsa110_init_irq,
+       .timer          = &ebsa110_timer,
 MACHINE_END