From: Andy P. <at...@us...> - 2002-04-10 18:38:57
|
Update of /cvsroot/linux-vax/kernel-2.4/arch/arm/mach-ebsa110 In directory usw-pr-cvs1:/tmp/cvs-serv24336/arm/mach-ebsa110 Added Files: Makefile arch.c hardware.h io.c irq.c leds.c mm.c time.c Log Message: synch 2.4.15 commit 32 --- NEW FILE --- # # Makefile for the linux kernel. # # Note! Dependencies are done automagically by 'make dep', which also # removes any old dependencies. DON'T put your own dependencies here # unless it's something special (ie not a .c file). USE_STANDARD_AS_RULE := true O_TARGET := ebsa110.o # Object file lists. obj-y := arch.o io.o irq.o mm.o time.o obj-m := obj-n := obj- := export-objs := io.o obj-$(CONFIG_LEDS) += leds.o include $(TOPDIR)/Rules.make --- NEW FILE --- /* * linux/arch/arm/mach-ebsa110/arch.c * * Architecture specific fixups. */ #include <linux/tty.h> #include <linux/delay.h> #include <linux/pm.h> #include <linux/init.h> #include <asm/elf.h> #include <asm/setup.h> #include <asm/mach-types.h> #include <asm/mach/arch.h> #include <asm/hardware/dec21285.h> extern void ebsa110_map_io(void); extern void ebsa110_init_irq(void); 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) MACHINE_END --- NEW FILE --- /* * linux/arch/arm/mach-ebsa110/hardware.h * * Copyright (C) 2001 Russell King * * Local hardware definitions. */ #ifndef HARDWARE_H #define HARDWARE_H #define IRQ_MASK 0xfe000000 /* read */ #define IRQ_MSET 0xfe000000 /* write */ #define IRQ_STAT 0xff000000 /* read */ #define IRQ_MCLR 0xff000000 /* write */ #endif --- NEW FILE --- /* * linux/arch/arm/mach-ebsa110/isamem.c * * Copyright (C) 2001 Russell King * * Perform "ISA" memory and IO accesses. The EBSA110 has some "peculiarities" * in the way it handles accesses to odd IO ports on 16-bit devices. These * devices have their D0-D15 lines connected to the processors D0-D15 lines. * Since they expect all byte IO operations to be performed on D0-D7, and the * StrongARM expects to transfer the byte to these odd addresses on D8-D15, * we must use a trick to get the required behaviour. * * The trick employed here is to use long word stores to odd address -1. The * glue logic picks this up as a "trick" access, and asserts the LSB of the * peripherals address bus, thereby accessing the odd IO port. Meanwhile, the * StrongARM transfers its data on D0-D7 as expected. * * Things get more interesting on the pass-1 EBSA110 - the PCMCIA controller * wiring was screwed in such a way that it had limited memory space access. * Luckily, the work-around for this is not too horrible. See * __isamem_convert_addr for the details. */ #include <linux/module.h> #include <linux/kernel.h> #include <linux/types.h> #include <asm/io.h> #include <asm/page.h> static u32 __isamem_convert_addr(void *addr) { u32 ret, a = (u32) addr; /* * The PCMCIA controller is wired up as follows: * +---------+---------+---------+---------+---------+---------+ * PCMCIA | 2 2 2 2 | 1 1 1 1 | 1 1 1 1 | 1 1 | | | * | 3 2 1 0 | 9 8 7 6 | 5 4 3 2 | 1 0 9 8 | 7 6 5 4 | 3 2 1 0 | * +---------+---------+---------+---------+---------+---------+ * CPU | 2 2 2 2 | 2 1 1 1 | 1 1 1 1 | 1 1 1 | | | * | 4 3 2 1 | 0 9 9 8 | 7 6 5 4 | 3 2 0 9 | 8 7 6 5 | 4 3 2 x | * +---------+---------+---------+---------+---------+---------+ * * This means that we can access PCMCIA regions as follows: * 0x*10000 -> 0x*1ffff * 0x*70000 -> 0x*7ffff * 0x*90000 -> 0x*9ffff * 0x*f0000 -> 0x*fffff */ ret = (a & 0xf803fe) << 1; ret |= (a & 0x03fc00) << 2; ret += 0xe8000000; if ((a & 0x20000) == (a & 0x40000) >> 1) return ret; BUG(); return 0; } /* * read[bwl] and write[bwl] */ u8 __readb(void *addr) { u32 ret, a = __isamem_convert_addr(addr); if ((int)addr & 1) ret = __arch_getl(a); else ret = __arch_getb(a); return ret; } u16 __readw(void *addr) { u32 a = __isamem_convert_addr(addr); if ((int)addr & 1) BUG(); return __arch_getw(a); } u32 __readl(void *addr) { u32 ret, a = __isamem_convert_addr(addr); if ((int)addr & 3) BUG(); ret = __arch_getw(a); ret |= __arch_getw(a + 4) << 16; return ret; } EXPORT_SYMBOL(__readb); EXPORT_SYMBOL(__readw); EXPORT_SYMBOL(__readl); void __writeb(u8 val, void *addr) { u32 a = __isamem_convert_addr(addr); if ((int)addr & 1) __arch_putl(val, a); else __arch_putb(val, a); } void __writew(u16 val, void *addr) { u32 a = __isamem_convert_addr(addr); if ((int)addr & 1) BUG(); __arch_putw(val, a); } void __writel(u32 val, void *addr) { u32 a = __isamem_convert_addr(addr); if ((int)addr & 3) BUG(); __arch_putw(val, a); __arch_putw(val >> 16, a + 4); } EXPORT_SYMBOL(__writeb); EXPORT_SYMBOL(__writew); EXPORT_SYMBOL(__writel); #define SUPERIO_PORT(p) \ (((p) >> 3) == (0x3f8 >> 3) || \ ((p) >> 3) == (0x2f8 >> 3) || \ ((p) >> 3) == (0x378 >> 3)) u8 __inb(int port) { u32 ret; /* * The SuperIO registers use sane addressing techniques... */ if (SUPERIO_PORT(port)) ret = __arch_getb(ISAIO_BASE + (port << 2)); else { u32 a = ISAIO_BASE + ((port & ~1) << 1); /* * Shame nothing else does */ if (port & 1) ret = __arch_getl(a); else ret = __arch_getb(a); } return ret; } u16 __inw(int port) { u32 ret; /* * The SuperIO registers use sane addressing techniques... */ if (SUPERIO_PORT(port)) ret = __arch_getw(ISAIO_BASE + (port << 2)); else { u32 a = ISAIO_BASE + ((port & ~1) << 1); /* * Shame nothing else does */ if (port & 1) BUG(); ret = __arch_getw(a); } return ret; } u32 __inl(int port) { BUG(); return 0; } EXPORT_SYMBOL(__inb); EXPORT_SYMBOL(__inw); EXPORT_SYMBOL(__inl); void __outb(u8 val, int port) { /* * The SuperIO registers use sane addressing techniques... */ if (SUPERIO_PORT(port)) __arch_putb(val, ISAIO_BASE + (port << 2)); else { u32 a = ISAIO_BASE + ((port & ~1) << 1); /* * Shame nothing else does */ if (port & 1) __arch_putl(val, a); else __arch_putb(val, a); } } void __outw(u16 val, int port) { u32 off; /* * The SuperIO registers use sane addressing techniques... */ if (SUPERIO_PORT(port)) off = port << 2; else { off = (port & ~1) << 1; if (port & 1) BUG(); } __arch_putw(val, ISAIO_BASE + off); } void __outl(u32 val, int port) { BUG(); } EXPORT_SYMBOL(__outb); EXPORT_SYMBOL(__outw); EXPORT_SYMBOL(__outl); extern void __arch_writesb(unsigned long virt, const void *from, int len); extern void __arch_writesw(unsigned long virt, const void *from, int len); extern void __arch_writesl(unsigned long virt, const void *from, int len); extern void __arch_readsb(unsigned long virt, void *from, int len); extern void __arch_readsw(unsigned long virt, void *from, int len); extern void __arch_readsl(unsigned long virt, void *from, int len); void outsb(unsigned int port, const void *from, int len) { u32 off; if (SUPERIO_PORT(port)) off = port << 2; else { off = (port & ~1) << 1; if (port & 1) BUG(); } __raw_writesb(ISAIO_BASE + off, from, len); } void insb(unsigned int port, void *from, int len) { u32 off; if (SUPERIO_PORT(port)) off = port << 2; else { off = (port & ~1) << 1; if (port & 1) BUG(); } __raw_readsb(ISAIO_BASE + off, from, len); } EXPORT_SYMBOL(outsb); EXPORT_SYMBOL(insb); void outsw(unsigned int port, const void *from, int len) { u32 off; if (SUPERIO_PORT(port)) off = port << 2; else { off = (port & ~1) << 1; if (port & 1) BUG(); } __raw_writesw(ISAIO_BASE + off, from, len); } void insw(unsigned int port, void *from, int len) { u32 off; if (SUPERIO_PORT(port)) off = port << 2; else { off = (port & ~1) << 1; if (port & 1) BUG(); } __raw_readsw(ISAIO_BASE + off, from, len); } EXPORT_SYMBOL(outsw); EXPORT_SYMBOL(insw); void outsl(unsigned int port, const void *from, int len) { panic("outsl not supported on this architecture"); } void insl(unsigned int port, void *from, int len) { panic("insl not supported on this architecture"); } --- NEW FILE --- /* * linux/arch/arm/mach-ebsa110/irq.c * * Copyright (C) 1996-1998 Russell King * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Changelog: * 22-08-1998 RMK Restructured IRQ routines */ #include <linux/init.h> #include <asm/mach/irq.h> #include <asm/hardware.h> #include <asm/io.h> #include <asm/irq.h> #include <asm/system.h> #include "hardware.h" static void ebsa110_mask_irq(unsigned int irq) { __raw_writeb(1 << irq, IRQ_MCLR); } static void ebsa110_unmask_irq(unsigned int irq) { __raw_writeb(1 << irq, IRQ_MSET); } void __init ebsa110_init_irq(void) { unsigned long flags; int irq; save_flags_cli (flags); __raw_writeb(0xff, IRQ_MCLR); __raw_writeb(0x55, IRQ_MSET); __raw_writeb(0x00, IRQ_MSET); if (__raw_readb(IRQ_MASK) != 0x55) while (1); __raw_writeb(0xff, IRQ_MCLR); /* clear all interrupt enables */ restore_flags (flags); for (irq = 0; irq < NR_IRQS; irq++) { irq_desc[irq].valid = 1; irq_desc[irq].probe_ok = 1; irq_desc[irq].mask_ack = ebsa110_mask_irq; irq_desc[irq].mask = ebsa110_mask_irq; irq_desc[irq].unmask = ebsa110_unmask_irq; } } --- NEW FILE --- /* * linux/arch/arm/mach-ebsa110/leds.c * * Copyright (C) 1998 Russell King * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * EBSA-110 LED control routines. We use the led as follows: * * - Red - toggles state every 50 timer interrupts */ #include <linux/module.h> #include <linux/spinlock.h> #include <linux/init.h> #include <asm/hardware.h> #include <asm/leds.h> #include <asm/system.h> #include <asm/mach-types.h> static spinlock_t leds_lock; static void ebsa110_leds_event(led_event_t ledevt) { unsigned long flags; spin_lock_irqsave(&leds_lock, flags); switch(ledevt) { case led_timer: *(volatile unsigned char *)SOFT_BASE ^= 128; break; default: break; } spin_unlock_irqrestore(&leds_lock, flags); } static int __init leds_init(void) { if (machine_is_ebsa110()) leds_event = ebsa110_leds_event; return 0; } __initcall(leds_init); --- NEW FILE --- /* * linux/arch/arm/mach-ebsa110/mm.c * * Copyright (C) 1998-1999 Russell King * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Extra MM routines for the EBSA-110 architecture */ #include <linux/mm.h> #include <linux/init.h> #include <asm/hardware.h> #include <asm/pgtable.h> #include <asm/page.h> #include <asm/mach/map.h> #include "hardware.h" static struct map_desc ebsa110_io_desc[] __initdata = { /* * sparse external-decode ISAIO space */ { IRQ_STAT, TRICK4_PHYS, PGDIR_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, /* IRQ_STAT/IRQ_MCLR */ { IRQ_MASK, TRICK3_PHYS, PGDIR_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, /* IRQ_MASK/IRQ_MSET */ { SOFT_BASE, TRICK1_PHYS, PGDIR_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, /* SOFT_BASE */ { PIT_BASE, TRICK0_PHYS, PGDIR_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, /* PIT_BASE */ /* * self-decode ISAIO space */ { ISAIO_BASE, ISAIO_PHYS, ISAIO_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, { ISAMEM_BASE, ISAMEM_PHYS, ISAMEM_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, LAST_DESC }; void __init ebsa110_map_io(void) { iotable_init(ebsa110_io_desc); } --- NEW FILE --- /* * linux/arch/arm/mach-ebsa110/time.c * * Copyright (C) 2001 Russell King * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ #include <linux/sched.h> #include <linux/init.h> #include <asm/io.h> #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) /* * If CLKBY7 is larger than this, then we must do software * division of the timer interrupt. */ #if CLKBY7 > 6553500 #define DIVISOR 2 #else #define DIVISOR 1 #endif /* * This is the counter value */ #define COUNT ((CLKBY7 + (DIVISOR * HZ / 2)) / (DIVISOR * HZ)) extern unsigned long (*gettimeoffset)(void); static unsigned long divisor; /* * 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 * (DIVISOR - divisor); offset -= count; /* * `offset' is in units of timer counts. Convert * offset to units of microseconds. */ offset = offset * (1000000 / HZ) / (COUNT * DIVISOR); return offset; } int ebsa110_reset_timer(void) { u32 count; /* 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); if (divisor == 0) divisor = DIVISOR; divisor -= 1; return divisor; } void __init ebsa110_setup_timer(void) { /* * Timer 1, mode 2, LSB/MSB */ __raw_writeb(0x70, PIT_CTRL); __raw_writeb(COUNT & 0xff, PIT_T1); __raw_writeb(COUNT >> 8, PIT_T1); divisor = DIVISOR - 1; gettimeoffset = ebsa110_gettimeoffset; } |