|
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;
}
|