X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=arch%2Farm%2Fmach-ebsa110%2Fcore.c;h=70dd12ef3c40da46521d35a8bc527e8c546716b8;hb=16c70f8c1b54b61c3b951b6fb220df250fe09b32;hp=5c14e04eae1be69e124f8d6b4e3b2d0d00c8c44b;hpb=5273a3df6485dc2ad6aa7ddd441b9a21970f003b;p=linux-2.6.git diff --git a/arch/arm/mach-ebsa110/core.c b/arch/arm/mach-ebsa110/core.c index 5c14e04ea..70dd12ef3 100644 --- a/arch/arm/mach-ebsa110/core.c +++ b/arch/arm/mach-ebsa110/core.c @@ -11,6 +11,8 @@ */ #include #include +#include +#include #include #include @@ -26,6 +28,8 @@ #include #include +#include + #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