Commit 320bcfc9 authored by Ralf Bächle's avatar Ralf Bächle Committed by Linus Torvalds

[PATCH] DEC update

An update of the code for the DECstations.  This also adds 64-bit support
for the R4000 versions of DEC's good old workstations.
parent d4da6773
......@@ -2,6 +2,10 @@
# Makefile for the DECstation family specific parts of the kernel
#
obj-y := int-handler.o setup.o irq.o time.o reset.o rtc-dec.o wbflush.o
obj-y := ecc-berr.o int-handler.o ioasic-irq.o kn02-irq.o reset.o \
rtc-dec.o setup.o time.o
obj-$(CONFIG_PROM_CONSOLE) += promcon.o
obj-$(CONFIG_CPU_HAS_WB) += wbflush.o
EXTRA_AFLAGS := $(CFLAGS)
......@@ -3,8 +3,8 @@
#
netboot: all
mipsel-linux-ld -N -G 0 -T ld.ecoff ../../boot/zImage \
built-in.o ramdisk.img -o nbImage
$(LD) -N -G 0 -T ld.ecoff ../../boot/zImage \
dec_boot.o ramdisk.img -o nbImage
obj-y := decstation.o
......
/*
* linux/arch/mips/dec/ecc-berr.c
*
* Bus error event handling code for systems equipped with ECC
* handling logic, i.e. DECstation/DECsystem 5000/200 (KN02),
* 5000/240 (KN03), 5000/260 (KN05) and DECsystem 5900 (KN03),
* 5900/260 (KN05) systems.
*
* Copyright (c) 2003 Maciej W. Rozycki
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/spinlock.h>
#include <linux/types.h>
#include <asm/addrspace.h>
#include <asm/bootinfo.h>
#include <asm/cpu.h>
#include <asm/processor.h>
#include <asm/system.h>
#include <asm/traps.h>
#include <asm/dec/ecc.h>
#include <asm/dec/kn02.h>
#include <asm/dec/kn03.h>
#include <asm/dec/kn05.h>
static volatile u32 *kn0x_erraddr;
static volatile u32 *kn0x_chksyn;
static inline void dec_ecc_be_ack(void)
{
*kn0x_erraddr = 0; /* any write clears the IRQ */
iob();
}
static int dec_ecc_be_backend(struct pt_regs *regs, int is_fixup, int invoker)
{
static const char excstr[] = "exception";
static const char intstr[] = "interrupt";
static const char cpustr[] = "CPU";
static const char dmastr[] = "DMA";
static const char readstr[] = "read";
static const char mreadstr[] = "memory read";
static const char writestr[] = "write";
static const char mwritstr[] = "partial memory write";
static const char timestr[] = "timeout";
static const char overstr[] = "overrun";
static const char eccstr[] = "ECC error";
const char *kind, *agent, *cycle, *event;
const char *status = "", *xbit = "", *fmt = "";
dma_addr_t address;
u16 syn = 0, sngl;
int i = 0;
u32 erraddr = *kn0x_erraddr;
u32 chksyn = *kn0x_chksyn;
int action = MIPS_BE_FATAL;
/* For non-ECC ack ASAP, so any subsequent errors get caught. */
if ((erraddr & (KN0X_EAR_VALID | KN0X_EAR_ECCERR)) == KN0X_EAR_VALID)
dec_ecc_be_ack();
kind = invoker ? intstr : excstr;
if (!(erraddr & KN0X_EAR_VALID)) {
/* No idea what happened. */
printk(KERN_ALERT "Unindentified bus error %s.\n", kind);
return action;
}
agent = (erraddr & KN0X_EAR_CPU) ? cpustr : dmastr;
if (erraddr & KN0X_EAR_ECCERR) {
/* An ECC error on a CPU or DMA transaction. */
cycle = (erraddr & KN0X_EAR_WRITE) ? mwritstr : mreadstr;
event = eccstr;
} else {
/* A CPU timeout or a DMA overrun. */
cycle = (erraddr & KN0X_EAR_WRITE) ? writestr : readstr;
event = (erraddr & KN0X_EAR_CPU) ? timestr : overstr;
}
address = erraddr & KN0X_EAR_ADDRESS;
/* For ECC errors on reads adjust for MT pipelining. */
if ((erraddr & (KN0X_EAR_WRITE | KN0X_EAR_ECCERR)) == KN0X_EAR_ECCERR)
address = (address & ~0xfffLL) | ((address - 5) & 0xfffLL);
address <<= 2;
/* Only CPU errors are fixable. */
if (erraddr & KN0X_EAR_CPU && is_fixup)
action = MIPS_BE_FIXUP;
if (erraddr & KN0X_EAR_ECCERR) {
static const u8 data_sbit[32] = {
0x4f, 0x4a, 0x52, 0x54, 0x57, 0x58, 0x5b, 0x5d,
0x23, 0x25, 0x26, 0x29, 0x2a, 0x2c, 0x31, 0x34,
0x0e, 0x0b, 0x13, 0x15, 0x16, 0x19, 0x1a, 0x1c,
0x62, 0x64, 0x67, 0x68, 0x6b, 0x6d, 0x70, 0x75,
};
static const u8 data_mbit[25] = {
0x07, 0x0d, 0x1f,
0x2f, 0x32, 0x37, 0x38, 0x3b, 0x3d, 0x3e,
0x43, 0x45, 0x46, 0x49, 0x4c, 0x51, 0x5e,
0x61, 0x6e, 0x73, 0x76, 0x79, 0x7a, 0x7c, 0x7f,
};
static const char sbestr[] = "corrected single";
static const char dbestr[] = "uncorrectable double";
static const char mbestr[] = "uncorrectable multiple";
if (!(address & 0x4))
syn = chksyn; /* Low bank. */
else
syn = chksyn >> 16; /* High bank. */
if (!(syn & KN0X_ESR_VLDLO)) {
/* Ack now, no rewrite will happen. */
dec_ecc_be_ack();
fmt = KERN_ALERT "%s" "invalid.\n";
} else {
sngl = syn & KN0X_ESR_SNGLO;
syn &= KN0X_ESR_SYNLO;
/*
* Multibit errors may be tagged incorrectly;
* check the syndrome explicitly.
*/
for (i = 0; i < 25; i++)
if (syn == data_mbit[i])
break;
if (i < 25) {
status = mbestr;
} else if (!sngl) {
status = dbestr;
} else {
volatile u32 *ptr = (void *)KSEG1ADDR(address);
*ptr = *ptr; /* Rewrite. */
iob();
status = sbestr;
action = MIPS_BE_DISCARD;
}
/* Ack now, now we've rewritten (or not). */
dec_ecc_be_ack();
if (syn && syn == (syn & -syn)) {
if (syn == 0x01) {
fmt = KERN_ALERT "%s"
"%#04x -- %s bit error "
"at check bit C%s.\n";
xbit = "X";
} else {
fmt = KERN_ALERT "%s"
"%#04x -- %s bit error "
"at check bit C%s%u.\n";
}
i = syn >> 2;
} else {
for (i = 0; i < 32; i++)
if (syn == data_sbit[i])
break;
if (i < 32)
fmt = KERN_ALERT "%s"
"%#04x -- %s bit error "
"at data bit D%s%u.\n";
else
fmt = KERN_ALERT "%s"
"%#04x -- %s bit error.\n";
}
}
}
if (action != MIPS_BE_FIXUP)
printk(KERN_ALERT "Bus error %s: %s %s %s at %#010lx.\n",
kind, agent, cycle, event, address);
if (action != MIPS_BE_FIXUP && erraddr & KN0X_EAR_ECCERR)
printk(fmt, " ECC syndrome ", syn, status, xbit, i);
return action;
}
int dec_ecc_be_handler(struct pt_regs *regs, int is_fixup)
{
return dec_ecc_be_backend(regs, is_fixup, 0);
}
void dec_ecc_be_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
int action = dec_ecc_be_backend(regs, 0, 1);
if (action == MIPS_BE_DISCARD)
return;
/*
* FIXME: Find affected processes and kill them, otherwise we
* must die.
*
* The interrupt is asynchronously delivered thus EPC and RA
* may be irrelevant, but are printed for a reference.
*/
printk(KERN_ALERT "Fatal bus interrupt, epc == %08lx, ra == %08lx\n",
regs->cp0_epc, regs->regs[31]);
die("Unrecoverable bus error", regs);
}
/*
* Initialization differs a bit between KN02 and KN03/KN05, so we
* need two variants. Once set up, all systems can be handled the
* same way.
*/
static inline void dec_kn02_be_init(void)
{
volatile u32 *csr = (void *)KN02_CSR_BASE;
unsigned long flags;
kn0x_erraddr = (void *)(KN02_SLOT_BASE + KN02_ERRADDR);
kn0x_chksyn = (void *)(KN02_SLOT_BASE + KN02_CHKSYN);
spin_lock_irqsave(&kn02_lock, flags);
/* Preset write-only bits of the Control Register cache. */
cached_kn02_csr = *csr | KN03_CSR_LEDS;
/* Set normal ECC detection and generation. */
cached_kn02_csr &= ~(KN02_CSR_DIAGCHK | KN02_CSR_DIAGGEN);
/* Enable ECC correction. */
cached_kn02_csr |= KN02_CSR_CORRECT;
*csr = cached_kn02_csr;
iob();
spin_unlock_irqrestore(&kn02_lock, flags);
}
static inline void dec_kn03_be_init(void)
{
volatile u32 *mcr = (void *)(KN03_SLOT_BASE + IOASIC_MCR);
volatile u32 *mbcs = (void *)(KN03_SLOT_BASE + KN05_MB_CSR);
kn0x_erraddr = (void *)(KN03_SLOT_BASE + IOASIC_ERRADDR);
kn0x_chksyn = (void *)(KN03_SLOT_BASE + IOASIC_CHKSYN);
/*
* Set normal ECC detection and generation, enable ECC correction.
* For KN05 we also need to make sure EE (?) is enabled in the MB.
* Otherwise DBE/IBE exceptions would be masked but bus error
* interrupts would still arrive, resulting in an inevitable crash
* if get_dbe() triggers one.
*/
*mcr = (*mcr & ~(KN03_MCR_DIAGCHK | KN03_MCR_DIAGGEN)) |
KN03_MCR_CORRECT;
if (current_cpu_data.cputype == CPU_R4400SC)
*mbcs |= KN05_MB_CSR_EE;
fast_iob();
}
void __init dec_ecc_be_init(void)
{
if (mips_machtype == MACH_DS5000_200)
dec_kn02_be_init();
else
dec_kn03_be_init();
/* Clear any leftover errors from the firmware. */
dec_ecc_be_ack();
}
This diff is collapsed.
/*
* linux/arch/mips/dec/ioasic-irq.c
*
* DEC I/O ASIC interrupts.
*
* Copyright (c) 2002, 2003 Maciej W. Rozycki
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
#include <linux/init.h>
#include <linux/irq.h>
#include <linux/spinlock.h>
#include <linux/types.h>
#include <asm/dec/ioasic.h>
#include <asm/dec/ioasic_addrs.h>
#include <asm/dec/ioasic_ints.h>
static spinlock_t ioasic_lock = SPIN_LOCK_UNLOCKED;
static int ioasic_irq_base;
static inline void unmask_ioasic_irq(unsigned int irq)
{
u32 simr;
simr = ioasic_read(IO_REG_SIMR);
simr |= (1 << (irq - ioasic_irq_base));
ioasic_write(IO_REG_SIMR, simr);
}
static inline void mask_ioasic_irq(unsigned int irq)
{
u32 simr;
simr = ioasic_read(IO_REG_SIMR);
simr &= ~(1 << (irq - ioasic_irq_base));
ioasic_write(IO_REG_SIMR, simr);
}
static inline void clear_ioasic_irq(unsigned int irq)
{
u32 sir;
sir = ~(1 << (irq - ioasic_irq_base));
ioasic_write(IO_REG_SIR, sir);
}
static inline void enable_ioasic_irq(unsigned int irq)
{
unsigned long flags;
spin_lock_irqsave(&ioasic_lock, flags);
unmask_ioasic_irq(irq);
spin_unlock_irqrestore(&ioasic_lock, flags);
}
static inline void disable_ioasic_irq(unsigned int irq)
{
unsigned long flags;
spin_lock_irqsave(&ioasic_lock, flags);
mask_ioasic_irq(irq);
spin_unlock_irqrestore(&ioasic_lock, flags);
}
static inline unsigned int startup_ioasic_irq(unsigned int irq)
{
enable_ioasic_irq(irq);
return 0;
}
#define shutdown_ioasic_irq disable_ioasic_irq
static inline void ack_ioasic_irq(unsigned int irq)
{
spin_lock(&ioasic_lock);
mask_ioasic_irq(irq);
spin_unlock(&ioasic_lock);
fast_iob();
}
static inline void end_ioasic_irq(unsigned int irq)
{
if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
enable_ioasic_irq(irq);
}
static struct hw_interrupt_type ioasic_irq_type = {
.typename = "IO-ASIC",
.startup = startup_ioasic_irq,
.shutdown = shutdown_ioasic_irq,
.enable = enable_ioasic_irq,
.disable = disable_ioasic_irq,
.ack = ack_ioasic_irq,
.end = end_ioasic_irq,
};
#define startup_ioasic_dma_irq startup_ioasic_irq
#define shutdown_ioasic_dma_irq shutdown_ioasic_irq
#define enable_ioasic_dma_irq enable_ioasic_irq
#define disable_ioasic_dma_irq disable_ioasic_irq
#define ack_ioasic_dma_irq ack_ioasic_irq
static inline void end_ioasic_dma_irq(unsigned int irq)
{
clear_ioasic_irq(irq);
fast_iob();
end_ioasic_irq(irq);
}
static struct hw_interrupt_type ioasic_dma_irq_type = {
.typename = "IO-ASIC-DMA",
.startup = startup_ioasic_dma_irq,
.shutdown = shutdown_ioasic_dma_irq,
.enable = enable_ioasic_dma_irq,
.disable = disable_ioasic_dma_irq,
.ack = ack_ioasic_dma_irq,
.end = end_ioasic_dma_irq,
};
void __init init_ioasic_irqs(int base)
{
int i;
/* Mask interrupts. */
ioasic_write(IO_REG_SIMR, 0);
fast_iob();
for (i = base; i < base + IO_INR_DMA; i++) {
irq_desc[i].status = IRQ_DISABLED;
irq_desc[i].action = 0;
irq_desc[i].depth = 1;
irq_desc[i].handler = &ioasic_irq_type;
}
for (; i < base + IO_IRQ_LINES; i++) {
irq_desc[i].status = IRQ_DISABLED;
irq_desc[i].action = 0;
irq_desc[i].depth = 1;
irq_desc[i].handler = &ioasic_dma_irq_type;
}
ioasic_irq_base = base;
}
/*
* Code to handle DECstation IRQs plus some generic interrupt stuff.
*
* Copyright (C) 1992 Linus Torvalds
* Copyright (C) 1994, 1995, 1996, 1997, 2000 Ralf Baechle
*/
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/kernel_stat.h>
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/types.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/timex.h>
#include <linux/slab.h>
#include <linux/random.h>
#include <linux/seq_file.h>
#include <asm/bitops.h>
#include <asm/bootinfo.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/mipsregs.h>
#include <asm/system.h>
#include <asm/dec/interrupts.h>
extern void dec_init_kn01(void);
extern void dec_init_kn230(void);
extern void dec_init_kn02(void);
extern void dec_init_kn02ba(void);
extern void dec_init_kn02ca(void);
extern void dec_init_kn03(void);
extern asmlinkage void decstation_handle_int(void);
unsigned long spurious_count = 0;
static inline void mask_irq(unsigned int irq_nr)
{
unsigned int dummy;
if (dec_interrupt[irq_nr].iemask) { /* This is an ASIC interrupt */
*imr &= ~dec_interrupt[irq_nr].iemask;
dummy = *imr;
dummy = *imr;
} else /* This is a cpu interrupt */
change_cp0_status(ST0_IM, read_32bit_cp0_register(CP0_STATUS) & ~dec_interrupt[irq_nr].cpu_mask);
}
static inline void unmask_irq(unsigned int irq_nr)
{
unsigned int dummy;
if (dec_interrupt[irq_nr].iemask) { /* This is an ASIC interrupt */
*imr |= dec_interrupt[irq_nr].iemask;
dummy = *imr;
dummy = *imr;
}
change_cp0_status(ST0_IM, read_32bit_cp0_register(CP0_STATUS) | dec_interrupt[irq_nr].cpu_mask);
}
void disable_irq(unsigned int irq_nr)
{
unsigned long flags;
save_and_cli(flags);
mask_irq(irq_nr);
restore_flags(flags);
}
void enable_irq(unsigned int irq_nr)
{
unsigned long flags;
save_and_cli(flags);
unmask_irq(irq_nr);
restore_flags(flags);
}
/*
* Pointers to the low-level handlers: first the general ones, then the
* fast ones, then the bad ones.
*/
extern void interrupt(void);
static struct irqaction *irq_action[32] =
{
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
};
int show_interrupts(struct seq_file *p, void *v)
{
int i;
struct irqaction *action;
unsigned long flags;
for (i = 0; i < 32; i++) {
local_irq_save(flags);
action = irq_action[i];
if (!action)
goto skip;
seq_printf(p, "%2d: %8d %c %s",
i, kstat_cpu(0).irqs[i],
(action->flags & SA_INTERRUPT) ? '+' : ' ',
action->name);
for (action = action->next; action; action = action->next) {
seq_printf(p, ",%s %s",
(action->flags & SA_INTERRUPT) ? " +" : "",
action->name);
}
seq_putc(p, '\n');
skip:
local_irq_restore(flags);
}
return 0;
}
/*
* do_IRQ handles IRQ's that have been installed without the
* SA_INTERRUPT flag: it uses the full signal-handling return
* and runs with other interrupts enabled. All relatively slow
* IRQ's should use this format: notably the keyboard/timer
* routines.
*/
asmlinkage void do_IRQ(int irq, struct pt_regs *regs)
{
struct irqaction *action;
int do_random, cpu;
cpu = smp_processor_id();
irq_enter(cpu, irq);
kstat_cpu(cpu).irqs[irq]++;
mask_irq(irq);
action = *(irq + irq_action);
if (action) {
if (!(action->flags & SA_INTERRUPT))
local_irq_enable();
action = *(irq + irq_action);
do_random = 0;
do {
do_random |= action->flags;
action->handler(irq, action->dev_id, regs);
action = action->next;
} while (action);
if (do_random & SA_SAMPLE_RANDOM)
add_interrupt_randomness(irq);
local_irq_disable();
unmask_irq(irq);
}
irq_exit(cpu, irq);
/* unmasking and bottom half handling is done magically for us. */
}
/*
* Idea is to put all interrupts
* in a single table and differenciate them just by number.
*/
int setup_dec_irq(int irq, struct irqaction *new)
{
int shared = 0;
struct irqaction *old, **p;
unsigned long flags;
p = irq_action + irq;
if ((old = *p) != NULL) {
/* Can't share interrupts unless both agree to */
if (!(old->flags & new->flags & SA_SHIRQ))
return -EBUSY;
/* Can't share interrupts unless both are same type */
if ((old->flags ^ new->flags) & SA_INTERRUPT)
return -EBUSY;
/* add new interrupt at end of irq queue */
do {
p = &old->next;
old = *p;
} while (old);
shared = 1;
}
if (new->flags & SA_SAMPLE_RANDOM)
rand_initialize_irq(irq);
save_and_cli(flags);
*p = new;
if (!shared) {
unmask_irq(irq);
}
restore_flags(flags);
return 0;
}
int request_irq(unsigned int irq,
void (*handler) (int, void *, struct pt_regs *),
unsigned long irqflags,
const char *devname,
void *dev_id)
{
int retval;
struct irqaction *action;
if (irq >= 32)
return -EINVAL;
if (!handler)
return -EINVAL;
action = (struct irqaction *) kmalloc(sizeof(struct irqaction), GFP_KERNEL);
if (!action)
return -ENOMEM;
action->handler = handler;
action->flags = irqflags;
action->mask = 0;
action->name = devname;
action->next = NULL;
action->dev_id = dev_id;
retval = setup_dec_irq(irq, action);
if (retval)
kfree(action);
return retval;
}
void free_irq(unsigned int irq, void *dev_id)
{
struct irqaction *action, **p;
unsigned long flags;
if (irq > 39) {
printk("Trying to free IRQ%d\n", irq);
return;
}
for (p = irq + irq_action; (action = *p) != NULL; p = &action->next) {
if (action->dev_id != dev_id)
continue;
/* Found it - now free it */
save_and_cli(flags);
*p = action->next;
if (!irq[irq_action])
mask_irq(irq);
restore_flags(flags);
kfree(action);
return;
}
printk("Trying to free free IRQ%d\n", irq);
}
unsigned long probe_irq_on(void)
{
/* TODO */
return 0;
}
int probe_irq_off(unsigned long irqs)
{
/* TODO */
return 0;
}
void __init init_IRQ(void)
{
switch (mips_machtype) {
case MACH_DS23100:
dec_init_kn01();
break;
case MACH_DS5100: /* DS5100 MIPSMATE */
dec_init_kn230();
break;
case MACH_DS5000_200: /* DS5000 3max */
dec_init_kn02();
break;
case MACH_DS5000_1XX: /* DS5000/100 3min */
dec_init_kn02ba();
break;
case MACH_DS5000_2X0: /* DS5000/240 3max+ */
dec_init_kn03();
break;
case MACH_DS5000_XX: /* Personal DS5000/2x */
dec_init_kn02ca();
break;
case MACH_DS5800: /* DS5800 Isis */
panic("Don't know how to set this up!");
break;
case MACH_DS5400: /* DS5400 MIPSfair */
panic("Don't know how to set this up!");
break;
case MACH_DS5500: /* DS5500 MIPSfair-2 */
panic("Don't know how to set this up!");
break;
}
set_except_vector(0, decstation_handle_int);
}
/*
* linux/arch/mips/dec/kn02-irq.c
*
* DECstation 5000/200 (KN02) Control and Status Register
* interrupts.
*
* Copyright (c) 2002, 2003 Maciej W. Rozycki
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
#include <linux/init.h>
#include <linux/irq.h>
#include <linux/spinlock.h>
#include <linux/types.h>
#include <asm/dec/kn02.h>
/*
* Bits 7:0 of the Control Register are write-only -- the
* corresponding bits of the Status Register have a different
* meaning. Hence we use a cache. It speeds up things a bit
* as well.
*
* There is no default value -- it has to be initialized.
*/
u32 cached_kn02_csr;
spinlock_t kn02_lock = SPIN_LOCK_UNLOCKED;
static int kn02_irq_base;
static inline void unmask_kn02_irq(unsigned int irq)
{
volatile u32 *csr = (volatile u32 *)KN02_CSR_BASE;
cached_kn02_csr |= (1 << (irq - kn02_irq_base + 16));
*csr = cached_kn02_csr;
}
static inline void mask_kn02_irq(unsigned int irq)
{
volatile u32 *csr = (volatile u32 *)KN02_CSR_BASE;
cached_kn02_csr &= ~(1 << (irq - kn02_irq_base + 16));
*csr = cached_kn02_csr;
}
static inline void enable_kn02_irq(unsigned int irq)
{
unsigned long flags;
spin_lock_irqsave(&kn02_lock, flags);
unmask_kn02_irq(irq);
spin_unlock_irqrestore(&kn02_lock, flags);
}
static inline void disable_kn02_irq(unsigned int irq)
{
unsigned long flags;
spin_lock_irqsave(&kn02_lock, flags);
mask_kn02_irq(irq);
spin_unlock_irqrestore(&kn02_lock, flags);
}
static unsigned int startup_kn02_irq(unsigned int irq)
{
enable_kn02_irq(irq);
return 0;
}
#define shutdown_kn02_irq disable_kn02_irq
static void ack_kn02_irq(unsigned int irq)
{
spin_lock(&kn02_lock);
mask_kn02_irq(irq);
spin_unlock(&kn02_lock);
iob();
}
static void end_kn02_irq(unsigned int irq)
{
if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
enable_kn02_irq(irq);
}
static struct hw_interrupt_type kn02_irq_type = {
.typename = "KN02-CSR",
.startup = startup_kn02_irq,
.shutdown = shutdown_kn02_irq,
.enable = enable_kn02_irq,
.disable = disable_kn02_irq,
.ack = ack_kn02_irq,
.end = end_kn02_irq,
};
void __init init_kn02_irqs(int base)
{
volatile u32 *csr = (volatile u32 *)KN02_CSR_BASE;
unsigned long flags;
int i;
/* Mask interrupts. */
spin_lock_irqsave(&kn02_lock, flags);
cached_kn02_csr &= ~KN03_CSR_IOINTEN;
*csr = cached_kn02_csr;
iob();
spin_unlock_irqrestore(&kn02_lock, flags);
for (i = base; i < base + KN02_IRQ_LINES; i++) {
irq_desc[i].status = IRQ_DISABLED;
irq_desc[i].action = 0;
irq_desc[i].depth = 1;
irq_desc[i].handler = &kn02_irq_type;
}
kn02_irq_base = base;
}
# $Id: Makefile,v 1.1 1999/01/17 03:49:44 ralf Exp $
#
# Makefile for the DECstation prom monitor library routines
# under Linux.
#
lib-y := init.o memory.o cmdline.o identify.o locore.o
lib-y += init.o memory.o cmdline.o identify.o
EXTRA_AFLAGS := $(CFLAGS)
lib-$(CONFIG_MIPS32) += locore.o
lib-$(CONFIG_MIPS64) += call_o32.o
dep:
$(CPP) $(CPPFLAGS) -M *.c > .depend
EXTRA_AFLAGS := $(CFLAGS)
/*
* arch/mips/dec/call_o32.S
*
* O32 interface for the 64 (or N32) ABI.
*
* Copyright (C) 2002 Maciej W. Rozycki
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
#include <asm/asm.h>
#include <asm/regdef.h>
/* Maximum number of arguments supported. Must be even! */
#define O32_ARGC 32
/* Number of static registers we save. */
#define O32_STATC 11
/* Frame size for both of the above. */
#define O32_FRAMESZ (4 * O32_ARGC + SZREG * O32_STATC)
.text
/*
* O32 function call dispatcher, for interfacing 32-bit ROM routines.
*
* The standard 64 (N32) calling sequence is supported, with a0
* holding a function pointer, a1-a7 -- its first seven arguments
* and the stack -- remaining ones (up to O32_ARGC, including a1-a7).
* Static registers, gp and fp are preserved, v0 holds a result.
* This code relies on the called o32 function for sp and ra
* restoration and thus both this dispatcher and the current stack
* have to be placed in a KSEGx (or KUSEG) address space. Any
* pointers passed have to point to addresses within one of these
* spaces as well.
*/
NESTED(call_o32, O32_FRAMESZ, ra)
REG_SUBU sp,O32_FRAMESZ
REG_S ra,O32_FRAMESZ-1*SZREG(sp)
REG_S fp,O32_FRAMESZ-2*SZREG(sp)
REG_S gp,O32_FRAMESZ-3*SZREG(sp)
REG_S s7,O32_FRAMESZ-4*SZREG(sp)
REG_S s6,O32_FRAMESZ-5*SZREG(sp)
REG_S s5,O32_FRAMESZ-6*SZREG(sp)
REG_S s4,O32_FRAMESZ-7*SZREG(sp)
REG_S s3,O32_FRAMESZ-8*SZREG(sp)
REG_S s2,O32_FRAMESZ-9*SZREG(sp)
REG_S s1,O32_FRAMESZ-10*SZREG(sp)
REG_S s0,O32_FRAMESZ-11*SZREG(sp)
move jp,a0
sll a0,a1,zero
sll a1,a2,zero
sll a2,a3,zero
sll a3,a4,zero
sw a5,0x10(sp)
sw a6,0x14(sp)
sw a7,0x18(sp)
PTR_LA t0,O32_FRAMESZ(sp)
PTR_LA t1,0x1c(sp)
li t2,O32_ARGC-7
1:
lw t3,(t0)
REG_ADDU t0,SZREG
sw t3,(t1)
REG_SUBU t2,1
REG_ADDU t1,4
bnez t2,1b
jalr jp
REG_L s0,O32_FRAMESZ-11*SZREG(sp)
REG_L s1,O32_FRAMESZ-10*SZREG(sp)
REG_L s2,O32_FRAMESZ-9*SZREG(sp)
REG_L s3,O32_FRAMESZ-8*SZREG(sp)
REG_L s4,O32_FRAMESZ-7*SZREG(sp)
REG_L s5,O32_FRAMESZ-6*SZREG(sp)
REG_L s6,O32_FRAMESZ-5*SZREG(sp)
REG_L s7,O32_FRAMESZ-4*SZREG(sp)
REG_L gp,O32_FRAMESZ-3*SZREG(sp)
REG_L fp,O32_FRAMESZ-2*SZREG(sp)
REG_L ra,O32_FRAMESZ-1*SZREG(sp)
REG_ADDU sp,O32_FRAMESZ
jr ra
END(call_o32)
......@@ -6,32 +6,30 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/types.h>
#include <asm/bootinfo.h>
#include "prom.h"
#include <asm/dec/prom.h>
#undef PROM_DEBUG
#ifdef PROM_DEBUG
extern int (*prom_printf)(char *, ...);
#endif
char arcs_cmdline[COMMAND_LINE_SIZE];
char arcs_cmdline[CL_SIZE];
void __init prom_init_cmdline(int argc, char **argv, unsigned long magic)
void __init prom_init_cmdline(s32 argc, s32 *argv, u32 magic)
{
char *arg;
int start_arg, i;
/*
* collect args and prepare cmd_line
*/
if (magic != REX_PROM_MAGIC)
if (!prom_is_rex(magic))
start_arg = 1;
else
start_arg = 2;
for (i = start_arg; i < argc; i++) {
strcat(arcs_cmdline, argv[i]);
arg = (void *)(long)(argv[i]);
strcat(arcs_cmdline, arg);
if (i < (argc - 1))
strcat(arcs_cmdline, " ");
}
......@@ -39,6 +37,4 @@ void __init prom_init_cmdline(int argc, char **argv, unsigned long magic)
#ifdef PROM_DEBUG
prom_printf("arcs_cmdline: %s\n", &(arcs_cmdline[0]));
#endif
}
......@@ -2,32 +2,104 @@
* identify.c: machine identification code.
*
* Copyright (C) 1998 Harald Koerfgen and Paul M. Antoine
*
* $Id: identify.c,v 1.2 1999/10/09 00:00:58 ralf Exp $
* Copyright (C) 2002, 2003 Maciej W. Rozycki
*/
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/mc146818rtc.h>
#include <linux/string.h>
#include <linux/types.h>
#include <asm/bootinfo.h>
#include <asm/dec/ioasic.h>
#include <asm/dec/ioasic_addrs.h>
#include <asm/dec/kn01.h>
#include <asm/dec/kn02.h>
#include <asm/dec/kn02ba.h>
#include <asm/dec/kn02ca.h>
#include <asm/dec/kn03.h>
#include <asm/dec/kn230.h>
#include <asm/dec/prom.h>
#include "dectypes.h"
#include "prom.h"
extern char *(*prom_getenv)(char *);
extern int (*prom_printf)(char *, ...);
extern int (*rex_getsysid)(void);
extern unsigned long mips_machgroup;
extern unsigned long mips_machtype;
void __init prom_identify_arch (unsigned int magic)
static const char *dec_system_strings[] = {
[MACH_DSUNKNOWN] "unknown DECstation",
[MACH_DS23100] "DECstation 2100/3100",
[MACH_DS5100] "DECsystem 5100",
[MACH_DS5000_200] "DECstation 5000/200",
[MACH_DS5000_1XX] "DECstation 5000/1xx",
[MACH_DS5000_XX] "Personal DECstation 5000/xx",
[MACH_DS5000_2X0] "DECstation 5000/2x0",
[MACH_DS5400] "DECsystem 5400",
[MACH_DS5500] "DECsystem 5500",
[MACH_DS5800] "DECsystem 5800",
[MACH_DS5900] "DECsystem 5900",
};
const char *get_system_type(void)
{
#define STR_BUF_LEN 64
static char system[STR_BUF_LEN];
static int called = 0;
if (called == 0) {
called = 1;
snprintf(system, STR_BUF_LEN, "Digital %s",
dec_system_strings[mips_machtype]);
}
return system;
}
/*
* Setup essential system-specific memory addresses. We need them
* early. Semantically the functions belong to prom/init.c, but they
* are compact enough we want them inlined. --macro
*/
static inline void prom_init_kn01(void)
{
dec_rtc_base = (void *)KN01_RTC_BASE;
dec_kn_slot_size = KN01_SLOT_SIZE;
}
static inline void prom_init_kn230(void)
{
dec_rtc_base = (void *)KN01_RTC_BASE;
dec_kn_slot_size = KN01_SLOT_SIZE;
}
static inline void prom_init_kn02(void)
{
dec_rtc_base = (void *)KN02_RTC_BASE;
dec_kn_slot_size = KN02_SLOT_SIZE;
}
static inline void prom_init_kn02xa(void)
{
ioasic_base = (void *)KN02XA_IOASIC_BASE;
dec_rtc_base = (void *)KN02XA_RTC_BASE;
dec_kn_slot_size = IOASIC_SLOT_SIZE;
}
static inline void prom_init_kn03(void)
{
unsigned char dec_cpunum, dec_firmrev, dec_etc;
int dec_systype;
unsigned long dec_sysid;
ioasic_base = (void *)KN03_IOASIC_BASE;
dec_rtc_base = (void *)KN03_RTC_BASE;
dec_kn_slot_size = IOASIC_SLOT_SIZE;
}
void __init prom_identify_arch(u32 magic)
{
unsigned char dec_cpunum, dec_firmrev, dec_etc, dec_systype;
u32 dec_sysid;
if (magic != REX_PROM_MAGIC) {
if (!prom_is_rex(magic)) {
dec_sysid = simple_strtoul(prom_getenv("systype"), (char **)0, 0);
} else {
dec_sysid = rex_getsysid();
......@@ -49,50 +121,52 @@ void __init prom_identify_arch (unsigned int magic)
* FIXME: This may not be an exhaustive list of DECStations/Servers!
* Put all model-specific initialisation calls here.
*/
prom_printf("This DECstation is a ");
switch (dec_systype) {
case DS2100_3100:
prom_printf("DS2100/3100\n");
mips_machtype = MACH_DS23100;
prom_init_kn01();
break;
case DS5100: /* DS5100 MIPSMATE */
prom_printf("DS5100\n");
mips_machtype = MACH_DS5100;
prom_init_kn230();
break;
case DS5000_200: /* DS5000 3max */
prom_printf("DS5000/200\n");
mips_machtype = MACH_DS5000_200;
prom_init_kn02();
break;
case DS5000_1XX: /* DS5000/100 3min */
prom_printf("DS5000/1xx\n");
mips_machtype = MACH_DS5000_1XX;
prom_init_kn02xa();
break;
case DS5000_2X0: /* DS5000/240 3max+ */
prom_printf("DS5000/2x0\n");
case DS5000_2X0: /* DS5000/240 3max+ or DS5900 bigmax */
mips_machtype = MACH_DS5000_2X0;
prom_init_kn03();
if (!(ioasic_read(IO_REG_SIR) & KN03_IO_INR_3MAXP))
mips_machtype = MACH_DS5900;
break;
case DS5000_XX: /* Personal DS5000/2x */
prom_printf("Personal DS5000/xx\n");
case DS5000_XX: /* Personal DS5000/xx maxine */
mips_machtype = MACH_DS5000_XX;
prom_init_kn02xa();
break;
case DS5800: /* DS5800 Isis */
prom_printf("DS5800\n");
mips_machtype = MACH_DS5800;
break;
case DS5400: /* DS5400 MIPSfair */
prom_printf("DS5400\n");
mips_machtype = MACH_DS5400;
break;
case DS5500: /* DS5500 MIPSfair-2 */
prom_printf("DS5500\n");
mips_machtype = MACH_DS5500;
break;
default:
prom_printf("unknown, id is %x", dec_systype);
mips_machtype = MACH_DSUNKNOWN;
break;
}
}
if (mips_machtype == MACH_DSUNKNOWN)
prom_printf("This is an %s, id is %x\n",
dec_system_strings[mips_machtype],
dec_systype);
else
prom_printf("This is a %s\n",
dec_system_strings[mips_machtype]);
}
......@@ -2,98 +2,103 @@
* init.c: PROM library initialisation code.
*
* Copyright (C) 1998 Harald Koerfgen
* Copyright (C) 2002 Maciej W. Rozycki
*/
#include <linux/init.h>
#include <linux/config.h>
#include <linux/init.h>
#include <linux/smp.h>
#include <linux/types.h>
#include <asm/bootinfo.h>
#include <asm/cpu.h>
#include "prom.h"
#include <asm/processor.h>
#include <asm/dec/prom.h>
/*
* PROM Interface (whichprom.c)
*/
typedef struct {
int pagesize;
unsigned char bitmap[0];
} memmap;
int (*rex_bootinit)(void);
int (*rex_bootread)(void);
int (*rex_getbitmap)(memmap *);
unsigned long *(*rex_slot_address)(int);
void *(*rex_gettcinfo)(void);
int (*rex_getsysid)(void);
void (*rex_clear_cache)(void);
int (*__rex_bootinit)(void);
int (*__rex_bootread)(void);
int (*__rex_getbitmap)(memmap *);
unsigned long *(*__rex_slot_address)(int);
void *(*__rex_gettcinfo)(void);
int (*__rex_getsysid)(void);
void (*__rex_clear_cache)(void);
int (*prom_getchar)(void);
char *(*prom_getenv)(char *);
int (*prom_printf)(char *, ...);
int (*__prom_getchar)(void);
char *(*__prom_getenv)(char *);
int (*__prom_printf)(char *, ...);
int (*pmax_open)(char*, int);
int (*pmax_lseek)(int, long, int);
int (*pmax_read)(int, void *, int);
int (*pmax_close)(int);
int (*__pmax_open)(char*, int);
int (*__pmax_lseek)(int, long, int);
int (*__pmax_read)(int, void *, int);
int (*__pmax_close)(int);
extern void prom_meminit(unsigned int);
extern void prom_identify_arch(unsigned int);
extern void prom_init_cmdline(int, char **, unsigned long);
/*
* Detect which PROM's the DECSTATION has, and set the callback vectors
* appropriately.
*/
void __init which_prom(unsigned long magic, int *prom_vec)
void __init which_prom(s32 magic, s32 *prom_vec)
{
/*
* No sign of the REX PROM's magic number means we assume a non-REX
* machine (i.e. we're on a DS2100/3100, DS5100 or DS5000/2xx)
*/
if (magic == REX_PROM_MAGIC)
{
if (prom_is_rex(magic)) {
/*
* Set up prom abstraction structure with REX entry points.
*/
rex_bootinit = (int (*)(void)) *(prom_vec + REX_PROM_BOOTINIT);
rex_bootread = (int (*)(void)) *(prom_vec + REX_PROM_BOOTREAD);
rex_getbitmap = (int (*)(memmap *)) *(prom_vec + REX_PROM_GETBITMAP);
prom_getchar = (int (*)(void)) *(prom_vec + REX_PROM_GETCHAR);
prom_getenv = (char *(*)(char *)) *(prom_vec + REX_PROM_GETENV);
rex_getsysid = (int (*)(void)) *(prom_vec + REX_PROM_GETSYSID);
rex_gettcinfo = (void *(*)(void)) *(prom_vec + REX_PROM_GETTCINFO);
prom_printf = (int (*)(char *, ...)) *(prom_vec + REX_PROM_PRINTF);
rex_slot_address = (unsigned long *(*)(int)) *(prom_vec + REX_PROM_SLOTADDR);
rex_clear_cache = (void (*)(void)) * (prom_vec + REX_PROM_CLEARCACHE);
}
else
{
__rex_bootinit =
(void *)(long)*(prom_vec + REX_PROM_BOOTINIT);
__rex_bootread =
(void *)(long)*(prom_vec + REX_PROM_BOOTREAD);
__rex_getbitmap =
(void *)(long)*(prom_vec + REX_PROM_GETBITMAP);
__prom_getchar =
(void *)(long)*(prom_vec + REX_PROM_GETCHAR);
__prom_getenv =
(void *)(long)*(prom_vec + REX_PROM_GETENV);
__rex_getsysid =
(void *)(long)*(prom_vec + REX_PROM_GETSYSID);
__rex_gettcinfo =
(void *)(long)*(prom_vec + REX_PROM_GETTCINFO);
__prom_printf =
(void *)(long)*(prom_vec + REX_PROM_PRINTF);
__rex_slot_address =
(void *)(long)*(prom_vec + REX_PROM_SLOTADDR);
__rex_clear_cache =
(void *)(long)*(prom_vec + REX_PROM_CLEARCACHE);
} else {
/*
* Set up prom abstraction structure with non-REX entry points.
*/
prom_getchar = (int (*)(void)) PMAX_PROM_GETCHAR;
prom_getenv = (char *(*)(char *)) PMAX_PROM_GETENV;
prom_printf = (int (*)(char *, ...)) PMAX_PROM_PRINTF;
pmax_open = (int (*)(char *, int)) PMAX_PROM_OPEN;
pmax_lseek = (int (*)(int, long, int)) PMAX_PROM_LSEEK;
pmax_read = (int (*)(int, void *, int)) PMAX_PROM_READ;
pmax_close = (int (*)(int)) PMAX_PROM_CLOSE;
__prom_getchar = (void *)PMAX_PROM_GETCHAR;
__prom_getenv = (void *)PMAX_PROM_GETENV;
__prom_printf = (void *)PMAX_PROM_PRINTF;
__pmax_open = (void *)PMAX_PROM_OPEN;
__pmax_lseek = (void *)PMAX_PROM_LSEEK;
__pmax_read = (void *)PMAX_PROM_READ;
__pmax_close = (void *)PMAX_PROM_CLOSE;
}
}
}
int __init prom_init(int argc, char **argv,
unsigned long magic, int *prom_vec)
int __init prom_init(s32 argc, s32 *argv, u32 magic, s32 *prom_vec)
{
extern void dec_machine_halt(void);
/* Determine which PROM's we have (and therefore which machine we're on!) */
/*
* Determine which PROM's we have
* (and therefore which machine we're on!)
*/
which_prom(magic, prom_vec);
if (magic == REX_PROM_MAGIC)
if (prom_is_rex(magic))
rex_clear_cache();
/* Were we compiled with the right CPU option? */
#if defined(CONFIG_CPU_R3000)
if ((mips_cpu.cputype == CPU_R4000SC) ||
(mips_cpu.cputype == CPU_R4400SC)) {
if ((current_cpu_data.cputype == CPU_R4000SC) ||
(current_cpu_data.cputype == CPU_R4400SC)) {
prom_printf("Sorry, this kernel is compiled for the wrong CPU type!\n");
prom_printf("Please recompile with \"CONFIG_CPU_R4x00 = y\"\n");
dec_machine_halt();
......@@ -101,8 +106,8 @@ int __init prom_init(int argc, char **argv,
#endif
#if defined(CONFIG_CPU_R4X00)
if ((mips_cpu.cputype == CPU_R3000) ||
(mips_cpu.cputype == CPU_R3000A)) {
if ((current_cpu_data.cputype == CPU_R3000) ||
(current_cpu_data.cputype == CPU_R3000A)) {
prom_printf("Sorry, this kernel is compiled for the wrong CPU type!\n");
prom_printf("Please recompile with \"CONFIG_CPU_R3000 = y\"\n");
dec_machine_halt();
......@@ -115,4 +120,3 @@ int __init prom_init(int argc, char **argv,
return 0;
}
......@@ -19,11 +19,11 @@ NESTED(genexcept_early, 0, sp)
mfc0 k0, CP0_STATUS
la k1, mem_err
sw k0,0(k1)
sw k0, 0(k1)
mfc0 k0, CP0_EPC
nop
addiu k0,4 # skip the causing instruction
addiu k0, 4 # skip the causing instruction
jr k0
rfe
END(genexcept_early)
......
......@@ -2,37 +2,22 @@
* memory.c: memory initialisation code.
*
* Copyright (C) 1998 Harald Koerfgen, Frieder Streffer and Paul M. Antoine
* Copyright (C) 2000 Maciej W. Rozycki
*
* $Id: memory.c,v 1.3 1999/10/09 00:00:58 ralf Exp $
* Copyright (C) 2000, 2002 Maciej W. Rozycki
*/
#include <linux/init.h>
#include <linux/config.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/bootmem.h>
#include <linux/types.h>
#include <asm/addrspace.h>
#include <asm/page.h>
#include <asm/bootinfo.h>
#include <asm/dec/machtype.h>
#include <asm/dec/prom.h>
#include <asm/page.h>
#include <asm/sections.h>
#include "prom.h"
typedef struct {
int pagesize;
unsigned char bitmap[0];
} memmap;
extern int (*rex_getbitmap)(memmap *);
#undef PROM_DEBUG
#ifdef PROM_DEBUG
extern int (*prom_printf)(char *, ...);
#endif
volatile unsigned long mem_err = 0; /* So we know an error occurred */
......@@ -43,10 +28,10 @@ volatile unsigned long mem_err = 0; /* So we know an error occurred */
#define CHUNK_SIZE 0x400000
static void __init pmax_setup_memory_region(void)
static inline void pmax_setup_memory_region(void)
{
volatile unsigned char *memory_page, dummy;
char old_handler[0x80];
char old_handler[0x80];
extern char genexcept_early;
/* Install exception handler */
......@@ -73,14 +58,14 @@ static void __init pmax_setup_memory_region(void)
* Use the REX prom calls to get hold of the memory bitmap, and thence
* determine memory size.
*/
static void __init rex_setup_memory_region(void)
static inline void rex_setup_memory_region(void)
{
int i, bitmap_size;
unsigned long mem_start = 0, mem_size = 0;
memmap *bm;
/* some free 64k */
bm = (memmap *) 0x80028000;
bm = (memmap *)KSEG0ADDR(0x28000);
bitmap_size = rex_getbitmap(bm);
......@@ -100,9 +85,9 @@ static void __init rex_setup_memory_region(void)
add_memory_region(mem_start, mem_size, BOOT_MEM_RAM);
}
void __init prom_meminit(unsigned int magic)
void __init prom_meminit(u32 magic)
{
if (magic != REX_PROM_MAGIC)
if (!prom_is_rex(magic))
pmax_setup_memory_region();
else
rex_setup_memory_region();
......@@ -111,14 +96,13 @@ void __init prom_meminit(unsigned int magic)
void __init prom_free_prom_memory (void)
{
unsigned long addr, end;
extern char _ftext;
/*
* Free everything below the kernel itself but leave
* the first page reserved for the exception handlers.
*/
#ifdef CONFIG_DECLANCE
#if defined(CONFIG_DECLANCE) || defined(CONFIG_DECLANCE_MODULE)
/*
* Leave 128 KB reserved for Lance memory for
* IOASIC DECstations.
......@@ -126,10 +110,10 @@ void __init prom_free_prom_memory (void)
* XXX: save this address for use in dec_lance.c?
*/
if (IOASIC)
end = __pa(&_ftext) - 0x00020000;
end = __pa(&_text) - 0x00020000;
else
#endif
end = __pa(&_ftext);
end = __pa(&_text);
addr = PAGE_SIZE;
while (addr < end) {
......
/*
* Miscellaneous definitions used to call the routines contained in the boot
* PROMs on various models of DECSTATION's.
* the rights to redistribute these changes.
*/
#ifndef __ASM_DEC_PROM_H
#define __ASM_DEC_PROM_H
/*
* PMAX/3MAX PROM entry points for DS2100/3100's and DS5000/2xx's. Many of
* these will work for MIPSen as well!
*/
#define VEC_RESET 0xBFC00000 /* Prom base address */
#define PMAX_PROM_ENTRY(x) (VEC_RESET+((x)*8)) /* Prom jump table */
#define PMAX_PROM_HALT PMAX_PROM_ENTRY(2) /* valid on MIPSen */
#define PMAX_PROM_AUTOBOOT PMAX_PROM_ENTRY(5) /* valid on MIPSen */
#define PMAX_PROM_OPEN PMAX_PROM_ENTRY(6)
#define PMAX_PROM_READ PMAX_PROM_ENTRY(7)
#define PMAX_PROM_CLOSE PMAX_PROM_ENTRY(10)
#define PMAX_PROM_LSEEK PMAX_PROM_ENTRY(11)
#define PMAX_PROM_GETCHAR PMAX_PROM_ENTRY(12)
#define PMAX_PROM_PUTCHAR PMAX_PROM_ENTRY(13) /* 12 on MIPSen */
#define PMAX_PROM_GETS PMAX_PROM_ENTRY(15)
#define PMAX_PROM_PRINTF PMAX_PROM_ENTRY(17)
#define PMAX_PROM_GETENV PMAX_PROM_ENTRY(33) /* valid on MIPSen */
/*
* Magic number indicating REX PROM available on DECSTATION. Found in
* register a2 on transfer of control to program from PROM.
*/
#define REX_PROM_MAGIC 0x30464354
/*
* 3MIN/MAXINE PROM entry points for DS5000/1xx's, DS5000/xx's, and
* DS5000/2x0.
*/
#define REX_PROM_GETBITMAP 0x84/4 /* get mem bitmap */
#define REX_PROM_GETCHAR 0x24/4 /* getch() */
#define REX_PROM_GETENV 0x64/4 /* get env. variable */
#define REX_PROM_GETSYSID 0x80/4 /* get system id */
#define REX_PROM_GETTCINFO 0xa4/4
#define REX_PROM_PRINTF 0x30/4 /* printf() */
#define REX_PROM_SLOTADDR 0x6c/4 /* slotaddr */
#define REX_PROM_BOOTINIT 0x54/4 /* open() */
#define REX_PROM_BOOTREAD 0x58/4 /* read() */
#define REX_PROM_CLEARCACHE 0x7c/4
#endif /* __ASM_DEC_PROM_H */
......@@ -2,7 +2,7 @@
* Wrap-around code for a console using the
* DECstation PROM io-routines.
*
* Copyright (c) 1998 Harald Koerfgen
* Copyright (c) 1998 Harald Koerfgen
*/
#include <linux/tty.h>
......@@ -12,50 +12,45 @@
#include <linux/console.h>
#include <linux/fs.h>
extern int (*prom_getchar) (void);
extern int (*prom_printf) (char *,...);
#include <asm/dec/prom.h>
static void prom_console_write(struct console *co, const char *s,
unsigned count)
{
unsigned i;
/*
* Now, do each character
*/
for (i = 0; i < count; i++) {
if (*s == 10)
prom_printf("%c", 13);
prom_printf("%c", *s++);
}
unsigned i;
/*
* Now, do each character
*/
for (i = 0; i < count; i++) {
if (*s == 10)
prom_printf("%c", 13);
prom_printf("%c", *s++);
}
}
static int __init prom_console_setup(struct console *co, char *options)
{
return 0;
}
static kdev_t prom_console_device(struct console *c)
{
return MKDEV(TTY_MAJOR, 64 + c->index);
return 0;
}
static struct console sercons =
{
.name = "ttyS",
.write = prom_console_write,
.device = prom_console_device,
.setup = prom_console_setup,
.flags = CON_PRINTBUFFER,
.index = -1,
.name = "ttyS",
.write = prom_console_write,
.setup = prom_console_setup,
.flags = CON_PRINTBUFFER,
.index = -1,
};
/*
* Register console.
*/
long __init prom_console_init(long kmem_start, long kmem_end)
static int __init prom_console_init(void)
{
register_console(&sercons);
return kmem_start;
register_console(&sercons);
return 0;
}
console_initcall(prom_console_init);
/*
* $Id: $
*
* Reset a DECstation machine.
* Reset a DECstation machine.
*
* Copyright (C) 199x the Anonymous
* Copyright (C) 2001, 2002, 2003 Maciej W. Rozycki
*/
void (*back_to_prom)(void) = (void (*)(void))0xBFC00000;
#include <asm/addrspace.h>
#include <asm/ptrace.h>
#define back_to_prom() (((void (*)(void))KSEG1ADDR(0x1fc00000))())
void dec_machine_restart(char *command)
{
......
......@@ -3,33 +3,38 @@
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
* RTC routines for DECstation style attached Dallas chip.
* RTC routines for DECstation style attached Dallas DS1287 chip.
*
* Copyright (C) 1998, 2001 by Ralf Baechle
* Copyright (C) 1998 by Harald Koerfgen
* Copyright (C) 2002 Maciej W. Rozycki
*/
#include <linux/mc146818rtc.h>
#include <linux/module.h>
#include <linux/types.h>
extern char *dec_rtc_base;
volatile u8 *dec_rtc_base;
static unsigned char dec_rtc_read_data(unsigned long addr)
{
return (dec_rtc_base[addr * 4]);
return dec_rtc_base[addr * 4];
}
static void dec_rtc_write_data(unsigned char data, unsigned long addr)
{
dec_rtc_base[addr * 4] = data;
dec_rtc_base[addr * 4] = data;
}
static int dec_rtc_bcd_mode(void)
{
return 0;
return 0;
}
struct rtc_ops dec_rtc_ops =
{
&dec_rtc_read_data,
&dec_rtc_write_data,
&dec_rtc_bcd_mode
struct rtc_ops dec_rtc_ops = {
&dec_rtc_read_data,
&dec_rtc_write_data,
&dec_rtc_bcd_mode
};
EXPORT_SYMBOL(dec_rtc_base);
This diff is collapsed.
......@@ -2,12 +2,14 @@
* linux/arch/mips/dec/time.c
*
* Copyright (C) 1991, 1992, 1995 Linus Torvalds
* Copyright (C) 2000 Maciej W. Rozycki
* Copyright (C) 2000, 2003 Maciej W. Rozycki
*
* This file contains the time handling details for PC-style clocks as
* found in some MIPS systems.
*
*/
#include <linux/bcd.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/sched.h>
......@@ -45,7 +47,9 @@ extern volatile unsigned long wall_jiffies;
/* This is for machines which generate the exact clock. */
#define USECS_PER_JIFFY (1000000/HZ)
#define USECS_PER_JIFFY_FRAC ((1000000ULL << 32) / HZ & 0xffffffff)
#define USECS_PER_JIFFY_FRAC ((u32)((1000000ULL << 32) / HZ))
#define TICK_SIZE (tick_nsec / 1000)
/* Cycle counter value at the previous timer interrupt.. */
......@@ -99,7 +103,7 @@ static unsigned long do_fast_gettimeoffset(void)
}
}
/* Get last timer tick in absolute kernel time */
count = read_32bit_cp0_register(CP0_COUNT);
count = read_c0_count();
/* .. relative to previous jiffy (32 bits is enough) */
count -= timerlo;
......@@ -110,7 +114,7 @@ static unsigned long do_fast_gettimeoffset(void)
: "r" (count), "r" (quotient));
/*
* Due to possible jiffies inconsistencies, we need to check
* Due to possible jiffies inconsistencies, we need to check
* the result so that we'll get a timer that is monotonic.
*/
if (res >= USECS_PER_JIFFY)
......@@ -140,7 +144,7 @@ static unsigned long do_ioasic_gettimeoffset(void)
}
}
/* Get last timer tick in absolute kernel time */
count = ioasic_read(FCTR);
count = ioasic_read(IO_REG_FCTR);
/* .. relative to previous jiffy (32 bits is enough) */
count -= timerlo;
......@@ -160,9 +164,9 @@ static unsigned long do_ioasic_gettimeoffset(void)
return res;
}
/* This function must be called with interrupts disabled
/* This function must be called with interrupts disabled
* It was inspired by Steve McCanne's microtime-i386 for BSD. -- jrs
*
*
* However, the pc-audio speaker driver changes the divisor so that
* it gets interrupted rather more often - it loads 64 into the
* counter rather than 11932! This has an adverse impact on
......@@ -176,7 +180,7 @@ static unsigned long do_ioasic_gettimeoffset(void)
* using either the RTC or the 8253 timer. The decision would be
* based on whether there was any other device around that needed
* to trample on the 8253. I'd set up the RTC to interrupt at 1024 Hz,
* and then do some jiggery to have a version of do_timer that
* and then do some jiggery to have a version of do_timer that
* advanced the clock by 1/1024 s. Every time that reached over 1/100
* of a second, then do all the old code. If the time was kept correct
* then do_gettimeoffset could just return 0 - there is no low order
......@@ -187,13 +191,11 @@ static unsigned long do_ioasic_gettimeoffset(void)
* often than every 120 us or so.
*
* Anyway, this needs more thought.... pjsg (1993-08-28)
*
*
* If you are really that interested, you should be reading
* comp.protocols.time.ntp!
*/
#define TICK_SIZE tick
static unsigned long do_slow_gettimeoffset(void)
{
/*
......@@ -206,57 +208,58 @@ static unsigned long do_slow_gettimeoffset(void)
static unsigned long (*do_gettimeoffset) (void) = do_slow_gettimeoffset;
/*
* This version of gettimeofday has near microsecond resolution.
* This version of gettimeofday has microsecond resolution
* and better than microsecond precision on fast x86 machines with TSC.
*/
void do_gettimeofday(struct timeval *tv)
{
unsigned long flags;
unsigned long seq;
unsigned long usec, sec;
do {
seq = read_seqbegin_irqsave(&xtime_lock, flags);
*tv = xtime;
tv->tv_usec += do_gettimeoffset();
/*
* xtime is atomically updated in timer_bh. jiffies - wall_jiffies
* is nonzero if the timer bottom half hasnt executed yet.
*/
if (jiffies - wall_jiffies)
tv->tv_usec += USECS_PER_JIFFY;
} while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
seq = read_seqbegin(&xtime_lock);
usec = do_gettimeoffset();
{
unsigned long lost = jiffies - wall_jiffies;
if (lost)
usec += lost * (1000000 / HZ);
}
sec = xtime.tv_sec;
usec += (xtime.tv_nsec / 1000);
} while (read_seqretry(&xtime_lock, seq));
if (tv->tv_usec >= 1000000) {
tv->tv_usec -= 1000000;
tv->tv_sec++;
while (usec >= 1000000) {
usec -= 1000000;
sec++;
}
tv->tv_sec = sec;
tv->tv_usec = usec;
}
void do_settimeofday(struct timeval *tv)
{
write_seqlock_irq(&xtime_lock);
/* This is revolting. We need to set the xtime.tv_usec
* correctly. However, the value in this location is
* is value at the last tick.
* Discover what correction gettimeofday
* would have done, and then undo it!
/*
* This is revolting. We need to set "xtime" correctly. However, the
* value in this location is the value at the most recent update of
* wall time. Discover what correction gettimeofday() would have
* made, and then undo it!
*/
tv->tv_usec -= do_gettimeoffset();
tv->tv_usec -= (jiffies - wall_jiffies) * (1000000 / HZ);
if (tv->tv_usec < 0) {
while (tv->tv_usec < 0) {
tv->tv_usec += 1000000;
tv->tv_sec--;
}
xtime = *tv;
xtime.tv_sec = tv->tv_sec;
xtime.tv_nsec = (tv->tv_usec * 1000);
time_adjust = 0; /* stop active adjtime() */
time_status |= STA_UNSYNC;
time_maxerror = NTP_PHASE_LIMIT;
time_esterror = NTP_PHASE_LIMIT;
write_sequnlock_irq(&xtime_lock);
}
......@@ -281,7 +284,7 @@ static int set_rtc_mmss(unsigned long nowtime)
cmos_minutes = CMOS_READ(RTC_MINUTES);
if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
BCD_TO_BIN(cmos_minutes);
cmos_minutes = BCD2BIN(cmos_minutes);
/*
* since we're only adjusting minutes and seconds,
......@@ -297,8 +300,8 @@ static int set_rtc_mmss(unsigned long nowtime)
if (abs(real_minutes - cmos_minutes) < 30) {
if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
BIN_TO_BCD(real_seconds);
BIN_TO_BCD(real_minutes);
real_seconds = BIN2BCD(real_seconds);
real_minutes = BIN2BCD(real_minutes);
}
CMOS_WRITE(real_seconds, RTC_SECONDS);
CMOS_WRITE(real_minutes, RTC_MINUTES);
......@@ -366,8 +369,8 @@ timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
if ((time_status & STA_UNSYNC) == 0
&& xtime.tv_sec > last_rtc_update + 660
&& xtime.tv_usec >= 500000 - tick / 2
&& xtime.tv_usec <= 500000 + tick / 2) {
&& (xtime.tv_nsec / 1000) >= 500000 - ((unsigned) TICK_SIZE) / 2
&& (xtime.tv_nsec / 1000) <= 500000 + ((unsigned) TICK_SIZE) / 2) {
if (set_rtc_mmss(xtime.tv_sec) == 0)
last_rtc_update = xtime.tv_sec;
else
......@@ -381,7 +384,7 @@ timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
rigged to be safe on the 386 - basically it's a hack, so don't look
closely for now.. */
/*smp_message_pass(MSG_ALL_BUT_SELF, MSG_RESCHEDULE, 0L, 0); */
write_sequnlock(&xtime_lock);
}
static void r4k_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
......@@ -392,7 +395,7 @@ static void r4k_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
* The cycle counter is only 32 bit which is good for about
* a minute at current count rates of upto 150MHz or so.
*/
count = read_32bit_cp0_register(CP0_COUNT);
count = read_c0_count();
timerhi += (count < timerlo); /* Wrap around */
timerlo = count;
......@@ -402,7 +405,7 @@ static void r4k_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
* update the timer[hi]/[lo] to make do_fast_gettimeoffset()
* quotient calc still valid. -arca
*/
write_32bit_cp0_register(CP0_COUNT, 0);
write_c0_count(0);
timerhi = timerlo = 0;
}
......@@ -417,7 +420,7 @@ static void ioasic_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
* The free-running counter is 32 bit which is good for about
* 2 minutes, 50 seconds at possible count rates of upto 25MHz.
*/
count = ioasic_read(FCTR);
count = ioasic_read(IO_REG_FCTR);
timerhi += (count < timerlo); /* Wrap around */
timerlo = count;
......@@ -427,15 +430,18 @@ static void ioasic_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
* update the timer[hi]/[lo] to make do_fast_gettimeoffset()
* quotient calc still valid. -arca
*/
ioasic_write(FCTR, 0);
ioasic_write(IO_REG_FCTR, 0);
timerhi = timerlo = 0;
}
timer_interrupt(irq, dev_id, regs);
}
struct irqaction irq0 = {timer_interrupt, SA_INTERRUPT, 0,
"timer", NULL, NULL};
struct irqaction irq0 = {
.handler = timer_interrupt,
.flags = SA_INTERRUPT,
.name = "timer",
};
void __init time_init(void)
{
......@@ -463,12 +469,12 @@ void __init time_init(void)
year = CMOS_READ(RTC_YEAR);
} while (sec != CMOS_READ(RTC_SECONDS));
if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
BCD_TO_BIN(sec);
BCD_TO_BIN(min);
BCD_TO_BIN(hour);
BCD_TO_BIN(day);
BCD_TO_BIN(mon);
BCD_TO_BIN(year);
sec = BCD2BIN(sec);
min = BCD2BIN(min);
hour = BCD2BIN(hour);
day = BCD2BIN(day);
mon = BCD2BIN(mon);
year = BCD2BIN(year);
}
/*
* The PROM will reset the year to either '72 or '73.
......@@ -480,15 +486,15 @@ void __init time_init(void)
write_seqlock_irq(&xtime_lock);
xtime.tv_sec = mktime(year, mon, day, hour, min, sec);
xtime.tv_usec = 0;
xtime.tv_nsec = 0;
write_sequnlock_irq(&xtime_lock);
if (mips_cpu.options & MIPS_CPU_COUNTER) {
write_32bit_cp0_register(CP0_COUNT, 0);
if (cpu_has_counter) {
write_c0_count(0);
do_gettimeoffset = do_fast_gettimeoffset;
irq0.handler = r4k_timer_interrupt;
} else if (IOASIC) {
ioasic_write(FCTR, 0);
ioasic_write(IO_REG_FCTR, 0);
do_gettimeoffset = do_ioasic_gettimeoffset;
irq0.handler = ioasic_timer_interrupt;
}
......
......@@ -11,15 +11,18 @@
* for more details.
*
* Copyright (C) 1998 Harald Koerfgen
* Copyright (C) 2002 Maciej W. Rozycki
*/
#include <asm/bootinfo.h>
#include <linux/init.h>
#include <asm/bootinfo.h>
#include <asm/system.h>
#include <asm/wbflush.h>
static void wbflush_kn01(void);
static void wbflush_kn210(void);
static void wbflush_kn02ba(void);
static void wbflush_kn03(void);
static void wbflush_mips(void);
void (*__wbflush) (void);
......@@ -27,28 +30,24 @@ void __init wbflush_setup(void)
{
switch (mips_machtype) {
case MACH_DS23100:
__wbflush = wbflush_kn01;
break;
case MACH_DS5100: /* DS5100 MIPSMATE */
__wbflush = wbflush_kn210;
break;
case MACH_DS5000_200: /* DS5000 3max */
__wbflush = wbflush_kn01;
break;
__wbflush = wbflush_kn01;
break;
case MACH_DS5100: /* DS5100 MIPSMATE */
__wbflush = wbflush_kn210;
break;
case MACH_DS5000_1XX: /* DS5000/100 3min */
__wbflush = wbflush_kn02ba;
break;
case MACH_DS5000_2X0: /* DS5000/240 3max+ */
__wbflush = wbflush_kn03;
break;
case MACH_DS5000_XX: /* Personal DS5000/2x */
__wbflush = wbflush_kn02ba;
break;
case MACH_DS5000_2X0: /* DS5000/240 3max+ */
case MACH_DS5900: /* DS5900 bigmax */
default:
__wbflush = wbflush_mips;
break;
}
}
/*
* For the DS3100 and DS5000/200 the writeback buffer functions
* For the DS3100 and DS5000/200 the R2020/R3220 writeback buffer functions
* as part of Coprocessor 0.
*/
static void wbflush_kn01(void)
......@@ -78,29 +77,16 @@ static void wbflush_kn210(void)
"mtc0\t$2,$12\n\t"
"nop\n\t"
".set\tpop"
: : :"$2", "$3");
}
/*
* Looks like some magic with the System Interrupt Mask Register
* in the famous IOASIC for kmins and maxines.
*/
static void wbflush_kn02ba(void)
{
asm(".set\tpush\n\t"
".set\tnoreorder\n\t"
"lui\t$2,0xbc04\n\t"
"lw\t$3,0x120($2)\n\t"
"lw\t$3,0x120($2)\n\t"
".set\tpop"
: : :"$2", "$3");
: : : "$2", "$3");
}
/*
* The DS500/2x0 doesn't need to write back the WB.
* I/O ASIC systems use a standard writeback buffer that gets flushed
* upon an uncached read.
*/
static void wbflush_kn03(void)
static void wbflush_mips(void)
{
__fast_iob();
}
#include <linux/module.h>
......
This diff is collapsed.
This diff is collapsed.
/*
* include/asm-mips/dec/ecc.h
*
* ECC handling logic definitions common to DECstation/DECsystem
* 5000/200 (KN02), 5000/240 (KN03), 5000/260 (KN05) and
* DECsystem 5900 (KN03), 5900/260 (KN05) systems.
*
* Copyright (C) 2003 Maciej W. Rozycki
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
#ifndef __ASM_MIPS_DEC_ECC_H
#define __ASM_MIPS_DEC_ECC_H
/*
* Error Address Register bits.
* The register is r/wc -- any write clears it.
*/
#define KN0X_EAR_VALID (1<<31) /* error data valid, bus IRQ */
#define KN0X_EAR_CPU (1<<30) /* CPU/DMA transaction */
#define KN0X_EAR_WRITE (1<<29) /* write/read transaction */
#define KN0X_EAR_ECCERR (1<<28) /* ECC/timeout or overrun */
#define KN0X_EAR_RES_27 (1<<27) /* unused */
#define KN0X_EAR_ADDRESS (0x7ffffff<<0) /* address involved */
/*
* Error Syndrome Register bits.
* The register is frozen when EAR.VALID is set, otherwise it records bits
* from the last memory read. The register is r/wc -- any write clears it.
*/
#define KN0X_ESR_VLDHI (1<<31) /* error data valid hi word */
#define KN0X_ESR_CHKHI (0x7f<<24) /* check bits read from mem */
#define KN0X_ESR_SNGHI (1<<23) /* single/double bit error */
#define KN0X_ESR_SYNHI (0x7f<<16) /* syndrome from ECC logic */
#define KN0X_ESR_VLDLO (1<<15) /* error data valid lo word */
#define KN0X_ESR_CHKLO (0x7f<<8) /* check bits read from mem */
#define KN0X_ESR_SNGLO (1<<7) /* single/double bit error */
#define KN0X_ESR_SYNLO (0x7f<<0) /* syndrome from ECC logic */
#ifndef __ASSEMBLY__
struct pt_regs;
extern void dec_ecc_be_init(void);
extern int dec_ecc_be_handler(struct pt_regs *regs, int is_fixup);
extern void dec_ecc_be_interrupt(int irq, void *dev_id, struct pt_regs *regs);
#endif
#endif /* __ASM_MIPS_DEC_ECC_H */
/*
/*
* Miscellaneous definitions used to initialise the interrupt vector table
* with the machine-specific interrupt routines.
*
......@@ -8,77 +8,118 @@
*
* Copyright (C) 1997 by Paul M. Antoine.
* reworked 1998 by Harald Koerfgen.
* Copyright (C) 2001, 2002, 2003 Maciej W. Rozycki
*/
#ifndef __ASM_DEC_INTERRUPTS_H
#define __ASM_DEC_INTERRUPTS_H
#ifndef __ASM_DEC_INTERRUPTS_H
#define __ASM_DEC_INTERRUPTS_H
#include <asm/mipsregs.h>
/*
* DECstation Interrupts
*/
/*
* This list reflects the priority of the Interrupts.
* Exception: on kmins we have to handle Memory Error
* Interrupts before the TC Interrupts.
* The list of possible system devices which provide an
* interrupt. Not all devices exist on a given system.
*/
#define CLOCK 0
#define SCSI_DMA_INT 1
#define SCSI_INT 2
#define ETHER 3
#define SERIAL 4
#define TC0 5
#define TC1 6
#define TC2 7
#define MEMORY 8
#define FPU 9
#define HALT 10
#define NR_INTS 11
#define DEC_IRQ_CASCADE 0 /* cascade from CSR or I/O ASIC */
/* Ordinary interrupts */
#define DEC_IRQ_AB_RECV 1 /* ACCESS.bus receive */
#define DEC_IRQ_AB_XMIT 2 /* ACCESS.bus transmit */
#define DEC_IRQ_DZ11 3 /* DZ11 (DC7085) serial */
#define DEC_IRQ_ASC 4 /* ASC (NCR53C94) SCSI */
#define DEC_IRQ_FLOPPY 5 /* 82077 FDC */
#define DEC_IRQ_FPU 6 /* R3k FPU */
#define DEC_IRQ_HALT 7 /* HALT button or from ACCESS.Bus */
#define DEC_IRQ_ISDN 8 /* Am79C30A ISDN */
#define DEC_IRQ_LANCE 9 /* LANCE (Am7990) Ethernet */
#define DEC_IRQ_BUS 10 /* memory, I/O bus read/write errors */
#define DEC_IRQ_PSU 11 /* power supply unit warning */
#define DEC_IRQ_RTC 12 /* DS1287 RTC */
#define DEC_IRQ_SCC0 13 /* SCC (Z85C30) serial #0 */
#define DEC_IRQ_SCC1 14 /* SCC (Z85C30) serial #1 */
#define DEC_IRQ_SII 15 /* SII (DC7061) SCSI */
#define DEC_IRQ_TC0 16 /* TURBOchannel slot #0 */
#define DEC_IRQ_TC1 17 /* TURBOchannel slot #1 */
#define DEC_IRQ_TC2 18 /* TURBOchannel slot #2 */
#define DEC_IRQ_TIMER 19 /* ARC periodic timer */
#define DEC_IRQ_VIDEO 20 /* framebuffer */
/* I/O ASIC DMA interrupts */
#define DEC_IRQ_ASC_MERR 21 /* ASC memory read error */
#define DEC_IRQ_ASC_ERR 22 /* ASC page overrun */
#define DEC_IRQ_ASC_DMA 23 /* ASC buffer pointer loaded */
#define DEC_IRQ_FLOPPY_ERR 24 /* FDC error */
#define DEC_IRQ_ISDN_ERR 25 /* ISDN memory read/overrun error */
#define DEC_IRQ_ISDN_RXDMA 26 /* ISDN recv buffer pointer loaded */
#define DEC_IRQ_ISDN_TXDMA 27 /* ISDN xmit buffer pointer loaded */
#define DEC_IRQ_LANCE_MERR 28 /* LANCE memory read error */
#define DEC_IRQ_SCC0A_RXERR 29 /* SCC0A (printer) receive overrun */
#define DEC_IRQ_SCC0A_RXDMA 30 /* SCC0A receive half page */
#define DEC_IRQ_SCC0A_TXERR 31 /* SCC0A xmit memory read/overrun */
#define DEC_IRQ_SCC0A_TXDMA 32 /* SCC0A transmit page end */
#define DEC_IRQ_AB_RXERR 33 /* ACCESS.bus receive overrun */
#define DEC_IRQ_AB_RXDMA 34 /* ACCESS.bus receive half page */
#define DEC_IRQ_AB_TXERR 35 /* ACCESS.bus xmit memory read/ovrn */
#define DEC_IRQ_AB_TXDMA 36 /* ACCESS.bus transmit page end */
#define DEC_IRQ_SCC1A_RXERR 37 /* SCC1A (modem) receive overrun */
#define DEC_IRQ_SCC1A_RXDMA 38 /* SCC1A receive half page */
#define DEC_IRQ_SCC1A_TXERR 39 /* SCC1A xmit memory read/overrun */
#define DEC_IRQ_SCC1A_TXDMA 40 /* SCC1A transmit page end */
/* TC5 & TC6 are virtual slots for KN02's onboard devices */
#define DEC_IRQ_TC5 DEC_IRQ_ASC /* virtual PMAZ-AA */
#define DEC_IRQ_TC6 DEC_IRQ_LANCE /* virtual PMAD-AA */
#define DEC_NR_INTS 41
/* Largest of cpu mask_nr tables. */
#define DEC_MAX_CPU_INTS 6
/* Largest of asic mask_nr tables. */
#define DEC_MAX_ASIC_INTS 9
#ifndef __ASSEMBLY__
/*
* Data structure to hide the differences between the DECstation Interrupts
*
* If asic_mask == NULL, the interrupt is directly handled by the CPU.
* Otherwise this Interrupt is handled the IRQ Controller.
* CPU interrupt bits common to all systems.
*/
#define DEC_CPU_INR_FPU 7 /* R3k FPU */
#define DEC_CPU_INR_SW1 1 /* software #1 */
#define DEC_CPU_INR_SW0 0 /* software #0 */
#define DEC_CPU_IRQ_BASE 0 /* first IRQ assigned to CPU */
typedef struct
{
unsigned int cpu_mask; /* checking and enabling interrupts in CP0 */
unsigned int iemask; /* enabling interrupts in IRQ Controller */
} decint_t;
#define DEC_CPU_IRQ_NR(n) ((n) + DEC_CPU_IRQ_BASE)
#define DEC_CPU_IRQ_MASK(n) (1 << ((n) + CAUSEB_IP))
#define DEC_CPU_IRQ_ALL (0xff << CAUSEB_IP)
extern volatile unsigned int *isr;
/* address of the interrupt status register */
extern volatile unsigned int *imr;
/* address of the interrupt mask register */
extern decint_t dec_interrupt[NR_INTS];
#ifndef __ASSEMBLY__
/*
* Interrupt table structure to hide differences between different
* systems such.
* Interrupt table structures to hide differences between systems.
*/
extern void *cpu_ivec_tbl[8];
extern long cpu_mask_tbl[8];
extern long cpu_irq_nr[8];
extern long asic_irq_nr[32];
extern long asic_mask_tbl[32];
typedef union { int i; void *p; } int_ptr;
extern int dec_interrupt[DEC_NR_INTS];
extern int_ptr cpu_mask_nr_tbl[DEC_MAX_CPU_INTS][2];
extern int_ptr asic_mask_nr_tbl[DEC_MAX_ASIC_INTS][2];
extern int cpu_fpu_mask;
/*
* Common interrupt routine prototypes for all DECStations
*/
extern void dec_intr_unimplemented(void);
extern void dec_intr_fpu(void);
extern void dec_intr_rtc(void);
extern void kn02_io_int(void);
extern void kn02xa_io_int(void);
extern void kn03_io_int(void);
extern void asic_dma_int(void);
extern void asic_all_int(void);
extern void kn02_all_int(void);
extern void cpu_all_int(void);
extern void kn02_io_int(void);
extern void kn02xa_io_int(void);
extern void kn03_io_int(void);
extern void dec_intr_unimplemented(void);
extern void asic_intr_unimplemented(void);
extern void asic_intr_unimplemented(void);
#endif /* __ASSEMBLY__ */
#endif
#endif
/*
* linux/asm-mips/dec/ioasic.h
* include/asm-mips/dec/ioasic.h
*
* Copyright (C) 2000 Maciej W. Rozycki
* DEC I/O ASIC access operations.
*
* DEC I/O ASIC access operations.
* Copyright (C) 2000, 2002, 2003 Maciej W. Rozycki
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
#ifndef __ASM_DEC_IOASIC_H
#define __ASM_DEC_IOASIC_H
extern volatile unsigned int *ioasic_base;
#include <linux/spinlock.h>
#include <linux/types.h>
extern spinlock_t ioasic_ssr_lock;
extern inline void ioasic_write(unsigned int reg, unsigned int v)
extern volatile u32 *ioasic_base;
static inline void ioasic_write(unsigned int reg, u32 v)
{
ioasic_base[reg / 4] = v;
}
extern inline unsigned int ioasic_read(unsigned int reg)
static inline u32 ioasic_read(unsigned int reg)
{
return ioasic_base[reg / 4];
}
extern void init_ioasic_irqs(int base);
#endif /* __ASM_DEC_IOASIC_H */
......@@ -10,74 +10,142 @@
* "DEC 3000 300/400/500/600/700/800/900 AXP Models System Programmer's Manual"
*
* and the Mach Sources
*
* Copyright (C) 199x the Anonymous
* Copyright (C) 2002, 2003 Maciej W. Rozycki
*/
#ifndef IOASIC_ADDRS_H
#define IOASIC_ADDRS_H
#define CHUNK_SIZE 0x00040000
#define SYSTEM_ROM (0*CHUNK_SIZE) /* ??? */
#define IOCTL (1*CHUNK_SIZE)
#define ESAR (2*CHUNK_SIZE)
#define LANCE (3*CHUNK_SIZE)
#define SCC0 (4*CHUNK_SIZE)
#define VDAC_HI (5*CHUNK_SIZE) /* maxine only */
#define SCC1 (6*CHUNK_SIZE)
#define VDAC_LO (7*CHUNK_SIZE) /* maxine only */
#define TOY (8*CHUNK_SIZE)
#define ISDN (9*CHUNK_SIZE) /* maxine only */
#define ERRADDR (9*CHUNK_SIZE) /* 3maxplus only */
#define CHKSYN (10*CHUNK_SIZE) /* 3maxplus only */
#define ACCESS_BUS (10*CHUNK_SIZE) /* maxine only */
#define MCR (11*CHUNK_SIZE) /* 3maxplus only */
#define FLOPPY (11*CHUNK_SIZE) /* maxine only */
#define SCSI (12*CHUNK_SIZE)
#define FLOPPY_DMA (13*CHUNK_SIZE) /* maxine only */
#define SCSI_DMA (14*CHUNK_SIZE)
#define RESERVED_4 (15*CHUNK_SIZE)
#ifndef __ASM_MIPS_DEC_IOASIC_ADDRS_H
#define __ASM_MIPS_DEC_IOASIC_ADDRS_H
#define IOASIC_SLOT_SIZE 0x00040000
/*
* Offsets for IOCTL registers (relative to (system_base + IOCTL))
* Address ranges decoded by the I/O ASIC for onboard devices.
*/
#define SCSI_DMA_P 0x00 /* SCSI DMA Pointer */
#define SCSI_DMA_BP 0x10 /* SCSI DMA Buffer Pointer */
#define LANCE_DMA_P 0x20 /* LANCE DMA Pointer */
#define SCC0_T_DMA_P 0x30 /* Communication Port 1 Transmit DMA Pointer */
#define SCC0_R_DMA_P 0x40 /* Communication Port 1 Receive DMA Pointer */
#define SCC1_T_DMA_P 0x50 /* Communication Port 2 Transmit DMA Pointer */
#define SCC1_R_DMA_P 0x60 /* Communication Port 2 Receive DMA Pointer */
#define FLOPPY_DMA_P 0x70 /* Floppy DMA Pointer */
#define ISDN_T_DMA_P 0x80 /* ISDN Transmit DMA Pointer */
#define ISDN_T_DMA_BP 0x90 /* ISDN Transmit DMA Buffer Pointer */
#define ISDN_R_DMA_P 0xa0 /* ISDN Receive DMA Pointer */
#define ISDN_R_DMA_BP 0xb0 /* ISDN Receive DMA Buffer Pointer */
#define SSR 0x100 /* System Support Register */
#define SIR 0x110 /* System Interrupt Register */
#define SIMR 0x120 /* System Interrupt Mask Register */
#define FCTR 0x1e0 /* Free-Running Counter */
#define IOASIC_SYS_ROM (0*IOASIC_SLOT_SIZE) /* system board ROM */
#define IOASIC_IOCTL (1*IOASIC_SLOT_SIZE) /* I/O ASIC */
#define IOASIC_ESAR (2*IOASIC_SLOT_SIZE) /* LANCE MAC address chip */
#define IOASIC_LANCE (3*IOASIC_SLOT_SIZE) /* LANCE Ethernet */
#define IOASIC_SCC0 (4*IOASIC_SLOT_SIZE) /* SCC #0 */
#define IOASIC_VDAC_HI (5*IOASIC_SLOT_SIZE) /* VDAC (maxine) */
#define IOASIC_SCC1 (6*IOASIC_SLOT_SIZE) /* SCC #1 (3min, 3max+) */
#define IOASIC_VDAC_LO (7*IOASIC_SLOT_SIZE) /* VDAC (maxine) */
#define IOASIC_TOY (8*IOASIC_SLOT_SIZE) /* RTC */
#define IOASIC_ISDN (9*IOASIC_SLOT_SIZE) /* ISDN (maxine) */
#define IOASIC_ERRADDR (9*IOASIC_SLOT_SIZE) /* bus error address (3max+) */
#define IOASIC_CHKSYN (10*IOASIC_SLOT_SIZE) /* ECC syndrome (3max+) */
#define IOASIC_ACC_BUS (10*IOASIC_SLOT_SIZE) /* ACCESS.bus (maxine) */
#define IOASIC_MCR (11*IOASIC_SLOT_SIZE) /* memory control (3max+) */
#define IOASIC_FLOPPY (11*IOASIC_SLOT_SIZE) /* FDC (maxine) */
#define IOASIC_SCSI (12*IOASIC_SLOT_SIZE) /* ASC SCSI */
#define IOASIC_FDC_DMA (13*IOASIC_SLOT_SIZE) /* FDC DMA (maxine) */
#define IOASIC_SCSI_DMA (14*IOASIC_SLOT_SIZE) /* ??? */
#define IOASIC_RES_15 (15*IOASIC_SLOT_SIZE) /* unused? */
/*
* Handle partial word SCSI DMA transfers
* Offsets for I/O ASIC registers (relative to (system_base + IOASIC_IOCTL)).
*/
#define SCSI_SCR 0x1b0
#define SCSI_SDR0 0x1c0
#define SCSI_SDR1 0x1d0
/* all systems */
#define IO_REG_SCSI_DMA_P 0x00 /* SCSI DMA Pointer */
#define IO_REG_SCSI_DMA_BP 0x10 /* SCSI DMA Buffer Pointer */
#define IO_REG_LANCE_DMA_P 0x20 /* LANCE DMA Pointer */
#define IO_REG_SCC0A_T_DMA_P 0x30 /* SCC0A Transmit DMA Pointer */
#define IO_REG_SCC0A_R_DMA_P 0x40 /* SCC0A Receive DMA Pointer */
/* except Maxine */
#define IO_REG_SCC1A_T_DMA_P 0x50 /* SCC1A Transmit DMA Pointer */
#define IO_REG_SCC1A_R_DMA_P 0x60 /* SCC1A Receive DMA Pointer */
/* Maxine */
#define IO_REG_AB_T_DMA_P 0x50 /* ACCESS.bus Transmit DMA Pointer */
#define IO_REG_AB_R_DMA_P 0x60 /* ACCESS.bus Receive DMA Pointer */
#define IO_REG_FLOPPY_DMA_P 0x70 /* Floppy DMA Pointer */
#define IO_REG_ISDN_T_DMA_P 0x80 /* ISDN Transmit DMA Pointer */
#define IO_REG_ISDN_T_DMA_BP 0x90 /* ISDN Transmit DMA Buffer Pointer */
#define IO_REG_ISDN_R_DMA_P 0xa0 /* ISDN Receive DMA Pointer */
#define IO_REG_ISDN_R_DMA_BP 0xb0 /* ISDN Receive DMA Buffer Pointer */
/* all systems */
#define IO_REG_DATA_0 0xc0 /* System Data Buffer 0 */
#define IO_REG_DATA_1 0xd0 /* System Data Buffer 1 */
#define IO_REG_DATA_2 0xe0 /* System Data Buffer 2 */
#define IO_REG_DATA_3 0xf0 /* System Data Buffer 3 */
/* all systems */
#define IO_REG_SSR 0x100 /* System Support Register */
#define IO_REG_SIR 0x110 /* System Interrupt Register */
#define IO_REG_SIMR 0x120 /* System Interrupt Mask Reg. */
#define IO_REG_SAR 0x130 /* System Address Register */
/* Maxine */
#define IO_REG_ISDN_T_DATA 0x140 /* ISDN Xmit Data Register */
#define IO_REG_ISDN_R_DATA 0x150 /* ISDN Receive Data Register */
/* all systems */
#define IO_REG_LANCE_SLOT 0x160 /* LANCE I/O Slot Register */
#define IO_REG_SCSI_SLOT 0x170 /* SCSI Slot Register */
#define IO_REG_SCC0A_SLOT 0x180 /* SCC0A DMA Slot Register */
/* except Maxine */
#define IO_REG_SCC1A_SLOT 0x190 /* SCC1A DMA Slot Register */
/* Maxine */
#define IO_REG_AB_SLOT 0x190 /* ACCESS.bus DMA Slot Register */
#define IO_REG_FLOPPY_SLOT 0x1a0 /* Floppy Slot Register */
/* all systems */
#define IO_REG_SCSI_SCR 0x1b0 /* SCSI Partial-Word DMA Control */
#define IO_REG_SCSI_SDR0 0x1c0 /* SCSI DMA Partial Word 0 */
#define IO_REG_SCSI_SDR1 0x1d0 /* SCSI DMA Partial Word 1 */
#define IO_REG_FCTR 0x1e0 /* Free-Running Counter */
#define IO_REG_RES_31 0x1f0 /* unused */
/*
* DMA defines for the System Support Register
* The upper 16 bits of the System Support Register are a part of the
* I/O ASIC's internal DMA engine and thus are common to all I/O ASIC
* machines. The exception is the Maxine, which makes use of the
* FLOPPY and ISDN bits (otherwise unused) and has a different SCC
* wiring.
*/
#define LANCE_DMA_EN (1UL<<16) /* LANCE DMA enable */
#define SCSI_DMA_EN (1UL<<17) /* SCSI DMA enable */
#define SCSI_DMA_DIR (1UL<<18) /* SCSI DMA direction */
#define ISDN_REC_DMA_EN (1UL<<19) /* ISDN receive DMA enable */
#define ISDN_TRN_DMA_EN (1UL<<20) /* ISDN transmit DMA enable */
#define FLOPPY_DMA_EN (1UL<<21) /* Floppy DMA enable */
#define FLOPPY_DMA_DIR (1UL<<22) /* Floppy DMA direction */
#define SCC1A_DMA_EN (1UL<<28) /* SCC1 Channel A DMA enable */
#define SCC1B_DMA_EN (1UL<<29) /* SCC1 Channel B DMA enable */
#define SCC0A_DMA_EN (1UL<<30) /* SCC0 Channel A DMA enable */
#define SCC0B_DMA_EN (1UL<<31) /* Scc0 Channel B DMA enable */
#endif
/* all systems */
#define IO_SSR_SCC0A_TX_DMA_EN (1<<31) /* SCC0A transmit DMA enable */
#define IO_SSR_SCC0A_RX_DMA_EN (1<<30) /* SCC0A receive DMA enable */
#define IO_SSR_RES_27 (1<<27) /* unused */
#define IO_SSR_RES_26 (1<<26) /* unused */
#define IO_SSR_RES_25 (1<<25) /* unused */
#define IO_SSR_RES_24 (1<<24) /* unused */
#define IO_SSR_RES_23 (1<<23) /* unused */
#define IO_SSR_SCSI_DMA_DIR (1<<18) /* SCSI DMA direction */
#define IO_SSR_SCSI_DMA_EN (1<<17) /* SCSI DMA enable */
#define IO_SSR_LANCE_DMA_EN (1<<16) /* LANCE DMA enable */
/* except Maxine */
#define IO_SSR_SCC1A_TX_DMA_EN (1<<29) /* SCC1A transmit DMA enable */
#define IO_SSR_SCC1A_RX_DMA_EN (1<<28) /* SCC1A receive DMA enable */
#define IO_SSR_RES_22 (1<<22) /* unused */
#define IO_SSR_RES_21 (1<<21) /* unused */
#define IO_SSR_RES_20 (1<<20) /* unused */
#define IO_SSR_RES_19 (1<<19) /* unused */
/* Maxine */
#define IO_SSR_AB_TX_DMA_EN (1<<29) /* ACCESS.bus xmit DMA enable */
#define IO_SSR_AB_RX_DMA_EN (1<<28) /* ACCESS.bus recv DMA enable */
#define IO_SSR_FLOPPY_DMA_DIR (1<<22) /* Floppy DMA direction */
#define IO_SSR_FLOPPY_DMA_EN (1<<21) /* Floppy DMA enable */
#define IO_SSR_ISDN_TX_DMA_EN (1<<20) /* ISDN transmit DMA enable */
#define IO_SSR_ISDN_RX_DMA_EN (1<<19) /* ISDN receive DMA enable */
/*
* The lower 16 bits are system-specific. Bits 15,11:8 are common and
* defined here. The rest is defined in system-specific headers.
*/
#define KN0X_IO_SSR_DIAGDN (1<<15) /* diagnostic jumper */
#define KN0X_IO_SSR_SCC_RST (1<<11) /* ~SCC0,1 (Z85C30) reset */
#define KN0X_IO_SSR_RTC_RST (1<<10) /* ~RTC (DS1287) reset */
#define KN0X_IO_SSR_ASC_RST (1<<9) /* ~ASC (NCR53C94) reset */
#define KN0X_IO_SSR_LANCE_RST (1<<8) /* ~LANCE (Am7990) reset */
#endif /* __ASM_MIPS_DEC_IOASIC_ADDRS_H */
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -28,7 +28,7 @@ extern void claim_tc_card(int);
*/
extern void release_tc_card(int);
/*
* Return base address of card in slot
* Return base address of card in slot
*/
extern unsigned long get_tc_base_addr(int);
/*
......
/*
/*
* Various TURBOchannel related stuff
*
* This file is subject to the terms and conditions of the GNU General Public
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment