Commit 3ad349a5 authored by Ralf Bächle's avatar Ralf Bächle Committed by Linus Torvalds

[PATCH] NEC DDB update

This updates the support for NEC's DDB series of evaluation boards.
parent 320bcfc9
/*
* arch/mips/ddb5074/nile4.c -- NEC Vrc-5074 Nile 4 support routines
*
* Copyright (C) 2000 Geert Uytterhoeven <geert@sonycom.com>
* Sony Software Development Center Europe (SDCE), Brussels
*/
#include <linux/kernel.h>
#include <linux/types.h>
#include <asm/nile4.h>
/*
* Physical Device Address Registers
*
* Note: 32 bit addressing only!
*/
void nile4_set_pdar(u32 pdar, u32 phys, u32 size, int width,
int on_memory_bus, int visible)
{
u32 maskbits;
u32 widthbits;
if (pdar > NILE4_BOOTCS || (pdar & 7)) {
printk("nile4_set_pdar: invalid pdar %d\n", pdar);
return;
}
if (pdar == NILE4_INTCS && size != 0x00200000) {
printk("nile4_set_pdar: INTCS size must be 2 MB\n");
return;
}
switch (size) {
#if 0 /* We don't support 4 GB yet */
case 0x100000000: /* 4 GB */
maskbits = 4;
break;
#endif
case 0x80000000: /* 2 GB */
maskbits = 5;
break;
case 0x40000000: /* 1 GB */
maskbits = 6;
break;
case 0x20000000: /* 512 MB */
maskbits = 7;
break;
case 0x10000000: /* 256 MB */
maskbits = 8;
break;
case 0x08000000: /* 128 MB */
maskbits = 9;
break;
case 0x04000000: /* 64 MB */
maskbits = 10;
break;
case 0x02000000: /* 32 MB */
maskbits = 11;
break;
case 0x01000000: /* 16 MB */
maskbits = 12;
break;
case 0x00800000: /* 8 MB */
maskbits = 13;
break;
case 0x00400000: /* 4 MB */
maskbits = 14;
break;
case 0x00200000: /* 2 MB */
maskbits = 15;
break;
case 0: /* OFF */
maskbits = 0;
break;
default:
printk("nile4_set_pdar: unsupported size %p\n", (void *) size);
return;
}
switch (width) {
case 8:
widthbits = 0;
break;
case 16:
widthbits = 1;
break;
case 32:
widthbits = 2;
break;
case 64:
widthbits = 3;
break;
default:
printk("nile4_set_pdar: unsupported width %d\n", width);
return;
}
nile4_out32(pdar, maskbits | (on_memory_bus ? 0x10 : 0) |
(visible ? 0x20 : 0) | (widthbits << 6) |
(phys & 0xffe00000));
nile4_out32(pdar + 4, 0);
/*
* When programming a PDAR, the register should be read immediately
* after writing it. This ensures that address decoders are properly
* configured.
*/
nile4_in32(pdar);
nile4_in32(pdar + 4);
}
/*
* PCI Master Registers
*
* Note: 32 bit addressing only!
*/
void nile4_set_pmr(u32 pmr, u32 type, u32 addr)
{
if (pmr != NILE4_PCIINIT0 && pmr != NILE4_PCIINIT1) {
printk("nile4_set_pmr: invalid pmr %d\n", pmr);
return;
}
switch (type) {
case NILE4_PCICMD_IACK: /* PCI Interrupt Acknowledge */
case NILE4_PCICMD_IO: /* PCI I/O Space */
case NILE4_PCICMD_MEM: /* PCI Memory Space */
case NILE4_PCICMD_CFG: /* PCI Configuration Space */
break;
default:
printk("nile4_set_pmr: invalid type %d\n", type);
return;
}
nile4_out32(pmr, (type << 1) | 0x10 | (addr & 0xffe00000));
nile4_out32(pmr + 4, 0);
}
/*
* Interrupt Programming
*/
void nile4_map_irq(int nile4_irq, int cpu_irq)
{
u32 offset, t;
offset = NILE4_INTCTRL;
if (nile4_irq >= 8) {
offset += 4;
nile4_irq -= 8;
}
t = nile4_in32(offset);
t &= ~(7 << (nile4_irq * 4));
t |= cpu_irq << (nile4_irq * 4);
nile4_out32(offset, t);
}
void nile4_map_irq_all(int cpu_irq)
{
u32 all, t;
all = cpu_irq;
all |= all << 4;
all |= all << 8;
all |= all << 16;
t = nile4_in32(NILE4_INTCTRL);
t &= 0x88888888;
t |= all;
nile4_out32(NILE4_INTCTRL, t);
t = nile4_in32(NILE4_INTCTRL + 4);
t &= 0x88888888;
t |= all;
nile4_out32(NILE4_INTCTRL + 4, t);
}
void nile4_enable_irq(int nile4_irq)
{
u32 offset, t;
offset = NILE4_INTCTRL;
if (nile4_irq >= 8) {
offset += 4;
nile4_irq -= 8;
}
t = nile4_in32(offset);
t |= 8 << (nile4_irq * 4);
nile4_out32(offset, t);
}
void nile4_disable_irq(int nile4_irq)
{
u32 offset, t;
offset = NILE4_INTCTRL;
if (nile4_irq >= 8) {
offset += 4;
nile4_irq -= 8;
}
t = nile4_in32(offset);
t &= ~(8 << (nile4_irq * 4));
nile4_out32(offset, t);
}
void nile4_disable_irq_all(void)
{
nile4_out32(NILE4_INTCTRL, 0);
nile4_out32(NILE4_INTCTRL + 4, 0);
}
u16 nile4_get_irq_stat(int cpu_irq)
{
return nile4_in16(NILE4_INTSTAT0 + cpu_irq * 2);
}
void nile4_enable_irq_output(int cpu_irq)
{
u32 t;
t = nile4_in32(NILE4_INTSTAT1 + 4);
t |= 1 << (16 + cpu_irq);
nile4_out32(NILE4_INTSTAT1, t);
}
void nile4_disable_irq_output(int cpu_irq)
{
u32 t;
t = nile4_in32(NILE4_INTSTAT1 + 4);
t &= ~(1 << (16 + cpu_irq));
nile4_out32(NILE4_INTSTAT1, t);
}
void nile4_set_pci_irq_polarity(int pci_irq, int high)
{
u32 t;
t = nile4_in32(NILE4_INTPPES);
if (high)
t &= ~(1 << (pci_irq * 2));
else
t |= 1 << (pci_irq * 2);
nile4_out32(NILE4_INTPPES, t);
}
void nile4_set_pci_irq_level_or_edge(int pci_irq, int level)
{
u32 t;
t = nile4_in32(NILE4_INTPPES);
if (level)
t |= 2 << (pci_irq * 2);
else
t &= ~(2 << (pci_irq * 2));
nile4_out32(NILE4_INTPPES, t);
}
void nile4_clear_irq(int nile4_irq)
{
nile4_out32(NILE4_INTCLR, 1 << nile4_irq);
}
void nile4_clear_irq_mask(u32 mask)
{
nile4_out32(NILE4_INTCLR, mask);
}
u8 nile4_i8259_iack(void)
{
u8 irq;
/* Set window 0 for interrupt acknowledge */
nile4_set_pmr(NILE4_PCIINIT0, NILE4_PCICMD_IACK, 0);
irq = *(volatile u8 *) NILE4_PCI_IACK_BASE;
/* Set window 0 for PCI I/O space */
nile4_set_pmr(NILE4_PCIINIT0, NILE4_PCICMD_IO, 0);
return irq;
}
#if 0
void nile4_dump_irq_status(void)
{
printk("CPUSTAT = %p:%p\n", (void *) nile4_in32(NILE4_CPUSTAT + 4),
(void *) nile4_in32(NILE4_CPUSTAT));
printk("INTCTRL = %p:%p\n", (void *) nile4_in32(NILE4_INTCTRL + 4),
(void *) nile4_in32(NILE4_INTCTRL));
printk("INTSTAT0 = %p:%p\n",
(void *) nile4_in32(NILE4_INTSTAT0 + 4),
(void *) nile4_in32(NILE4_INTSTAT0));
printk("INTSTAT1 = %p:%p\n",
(void *) nile4_in32(NILE4_INTSTAT1 + 4),
(void *) nile4_in32(NILE4_INTSTAT1));
printk("INTCLR = %p:%p\n", (void *) nile4_in32(NILE4_INTCLR + 4),
(void *) nile4_in32(NILE4_INTCLR));
printk("INTPPES = %p:%p\n", (void *) nile4_in32(NILE4_INTPPES + 4),
(void *) nile4_in32(NILE4_INTPPES));
}
#endif
/*
* arch/mips/ddb5074/pci.c -- NEC DDB Vrc-5074 PCI access routines
*
* Copyright (C) 2000 Geert Uytterhoeven <geert@sonycom.com>
* Albert Dorofeev <albert@sonycom.com>
* Sony Software Development Center Europe (SDCE), Brussels
*/
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/pci.h>
#include <linux/types.h>
#include <linux/sched.h>
#include <linux/ioport.h>
#include <asm/nile4.h>
static u32 nile4_pre_pci_access0(int slot_num)
{
u32 pci_addr = 0;
u32 virt_addr = NILE4_PCI_CFG_BASE;
/* Set window 1 address 8000000 - 64 bit - 2 MB (PCI config space) */
nile4_set_pdar(NILE4_PCIW1, PHYSADDR(virt_addr), 0x00200000, 64, 0,
0);
if (slot_num > 2)
pci_addr = 0x00040000 << slot_num;
else
virt_addr += 0x00040000 << slot_num;
nile4_set_pmr(NILE4_PCIINIT1, NILE4_PCICMD_CFG, pci_addr);
return virt_addr;
}
static void nile4_post_pci_access0(void)
{
/*
* Set window 1 back to address 8000000 - 64 bit - 128 MB
* (PCI IO space)
*/
nile4_set_pdar(NILE4_PCIW1, PHYSADDR(NILE4_PCI_MEM_BASE),
0x08000000, 64, 1, 1);
nile4_set_pmr(NILE4_PCIINIT1, NILE4_PCICMD_MEM, 0);
}
static int nile4_pci_read(struct pci_bus *bus, unsigned int devfn, int where,
int size, u32 * val)
{
int status, slot_num, func_num;
u32 result, base;
switch (size) {
case 4:
/*
* For starters let's do configuration cycle 0 only
* (one bus only)
*/
if (bus->number)
return PCIBIOS_FUNC_NOT_SUPPORTED;
slot_num = PCI_SLOT(devfn);
func_num = PCI_FUNC(devfn);
if (slot_num == 5) {
/*
* This is Nile 4 and it will crash if we access it
* like other devices
*/
*val = nile4_in32(NILE4_PCI_BASE + where);
return PCIBIOS_SUCCESSFUL;
}
base = nile4_pre_pci_access0(slot_num);
*val = *((volatile u32 *) (base + (func_num << 8) +
(where & 0xfc)));
nile4_post_pci_access0();
return PCIBIOS_SUCCESSFUL;
case 2:
status = nile4_pci_read(bus, devfn, where, 4, &result);
if (status != PCIBIOS_SUCCESSFUL)
return status;
if (where & 2)
result >>= 16;
*val = (u16)(result & 0xffff);
break;
case 1:
status = nile4_pci_read(bus, devfn, where, 4, &result);
if (status != PCIBIOS_SUCCESSFUL)
return status;
if (where & 1)
result >>= 8;
if (where & 2)
result >>= 16;
*val = (u8)(result & 0xff);
break;
}
return PCIBIOS_SUCCESSFUL;
}
static int nile4_pci_write(struct pci_bus *bus, unsigned int devfn, int where,
int size, u32 val)
{
int status, slot_num, func_num, shift = 0;
u32 result, base;
switch (size) {
case 4:
/*
* For starters let's do configuration cycle 0 only
* (one bus only)
*/
if (bus->number)
return PCIBIOS_FUNC_NOT_SUPPORTED;
slot_num = PCI_SLOT(devfn);
func_num = PCI_FUNC(devfn);
if (slot_num == 5) {
/*
* This is Nile 4 and it will crash if we access
* it like other devices
*/
nile4_out32(NILE4_PCI_BASE + where, val);
return PCIBIOS_SUCCESSFUL;
}
base = nile4_pre_pci_access0(slot_num);
*((volatile u32 *) (base + (func_num << 8) +
(where & 0xfc))) = val;
nile4_post_pci_access0();
return PCIBIOS_SUCCESSFUL;
case 2:
status = nile4_pci_read(bus, devfn, where, 4, &result);
if (status != PCIBIOS_SUCCESSFUL)
return status;
if (where & 2)
shift += 16;
result &= ~(0xffff << shift);
result |= (u16)(val << shift);
break;
case 1:
status = nile4_pci_read(bus, devfn, where, 4, &result);
if (status != PCIBIOS_SUCCESSFUL)
return status;
if (where & 2)
shift += 16;
if (where & 1)
shift += 8;
result &= ~(0xff << shift);
result |= (u8)(val << shift);
break;
}
return nile4_pci_write(bus, devfn, where, 4, result);
}
struct pci_ops nile4_pci_ops = {
.read = nile4_pci_read,
.write = nile4_pci_write,
};
struct {
struct resource ram;
struct resource flash;
struct resource isa_io;
struct resource pci_io;
struct resource isa_mem;
struct resource pci_mem;
struct resource nile4;
struct resource boot;
} ddb5074_resources = {
{ "RAM", 0x00000000, 0x03ffffff,
IORESOURCE_MEM | PCI_BASE_ADDRESS_MEM_TYPE_64},
{ "Flash ROM", 0x04000000, 0x043fffff},
{ "Nile4 ISA I/O", 0x06000000, 0x060fffff},
{ "Nile4 PCI I/O", 0x06100000, 0x07ffffff},
{ "Nile4 ISA mem", 0x08000000, 0x08ffffff, IORESOURCE_MEM},
{ "Nile4 PCI mem", 0x09000000, 0x0fffffff, IORESOURCE_MEM},
{ "Nile4 ctrl", 0x1fa00000, 0x1fbfffff,
IORESOURCE_MEM | PCI_BASE_ADDRESS_MEM_TYPE_64},
{ "Boot ROM", 0x1fc00000, 0x1fffffff}
};
static void __init ddb5074_pci_fixup(void)
{
struct pci_dev *dev = NULL;
while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
if (dev->vendor == PCI_VENDOR_ID_NEC &&
dev->device == PCI_DEVICE_ID_NEC_NILE4) {
/*
* The first 64-bit PCI base register should point to
* the Nile4 control registers. Unfortunately this
* isn't the case, so we fix it ourselves. This allows
* the serial driver to find the UART.
*/
dev->resource[0] = ddb5074_resources.nile4;
request_resource(&iomem_resource,
&dev->resource[0]);
/*
* The second 64-bit PCI base register points to the
* first memory bank. Unfortunately the address is
* wrong, so we fix it (again).
*/
dev->resource[2] = ddb5074_resources.ram;
request_resource(&iomem_resource,
&dev->resource[2]);
} else if (dev->vendor == PCI_VENDOR_ID_AL
&& dev->device == PCI_DEVICE_ID_AL_M7101) {
/*
* It's nice to have the LEDs on the GPIO pins
* available for debugging
*/
extern struct pci_dev *pci_pmu;
u8 t8;
pci_pmu = dev; /* for LEDs D2 and D3 */
/* Program the lines for LEDs D2 and D3 to output */
nile4_pci_read_config_byte(dev, 0x7d, &t8);
t8 |= 0xc0;
nile4_pci_write_config_byte(dev, 0x7d, t8);
/* Turn LEDs D2 and D3 off */
nile4_pci_read_config_byte(dev, 0x7e, &t8);
t8 |= 0xc0;
nile4_pci_write_config_byte(dev, 0x7e, t8);
}
}
}
static void __init pcibios_fixup_irqs(void)
{
struct pci_dev *dev = NULL;
int slot_num;
while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
slot_num = PCI_SLOT(dev->devfn);
switch (slot_num) {
case 0:
dev->irq = nile4_to_irq(NILE4_INT_INTE);
break;
case 1:
dev->irq = nile4_to_irq(NILE4_INT_INTA);
break;
case 2: /* slot 1 */
dev->irq = nile4_to_irq(NILE4_INT_INTA);
break;
case 3: /* slot 2 */
dev->irq = nile4_to_irq(NILE4_INT_INTB);
break;
case 4: /* slot 3 */
dev->irq = nile4_to_irq(NILE4_INT_INTC);
break;
case 5:
/*
* Fixup so the serial driver can use the UART
*/
dev->irq = nile4_to_irq(NILE4_INT_UART);
break;
case 13:
dev->irq = nile4_to_irq(NILE4_INT_INTE);
break;
default:
break;
}
}
}
void __init pcibios_init(void)
{
printk("PCI: Probing PCI hardware\n");
ioport_resource.end = 0x1ffffff; /* 32 MB */
iomem_resource.end = 0x1fffffff; /* 512 MB */
/* `ram' and `nile4' are requested through the Nile4 pci_dev */
request_resource(&iomem_resource, &ddb5074_resources.flash);
request_resource(&iomem_resource, &ddb5074_resources.isa_io);
request_resource(&iomem_resource, &ddb5074_resources.pci_io);
request_resource(&iomem_resource, &ddb5074_resources.isa_mem);
request_resource(&iomem_resource, &ddb5074_resources.pci_mem);
request_resource(&iomem_resource, &ddb5074_resources.boot);
pci_scan_bus(0, &nile4_pci_ops, NULL);
ddb5074_pci_fixup();
pci_assign_unassigned_resources();
pcibios_fixup_irqs();
}
void __init pcibios_fixup_bus(struct pci_bus *bus)
{
bus->resource[1] = &ddb5074_resources.pci_mem;
}
char *pcibios_setup(char *str)
{
return str;
}
void __init pcibios_update_irq(struct pci_dev *dev, int irq)
{
pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
}
int pcibios_enable_resources(struct pci_dev *dev)
{
u16 cmd, old_cmd;
int idx;
struct resource *r;
/*
* Don't touch the Nile 4
*/
if (dev->vendor == PCI_VENDOR_ID_NEC &&
dev->device == PCI_DEVICE_ID_NEC_NILE4) return 0;
pci_read_config_word(dev, PCI_COMMAND, &cmd);
old_cmd = cmd;
for (idx = 0; idx < 6; idx++) {
r = &dev->resource[idx];
if (!r->start && r->end) {
printk(KERN_ERR "PCI: Device %s not available because "
"of resource collisions\n", dev->slot_name);
return -EINVAL;
}
if (r->flags & IORESOURCE_IO)
cmd |= PCI_COMMAND_IO;
if (r->flags & IORESOURCE_MEM)
cmd |= PCI_COMMAND_MEMORY;
}
if (cmd != old_cmd) {
printk("PCI: Enabling device %s (%04x -> %04x)\n",
dev->slot_name, old_cmd, cmd);
pci_write_config_word(dev, PCI_COMMAND, cmd);
}
return 0;
}
int pcibios_enable_device(struct pci_dev *dev)
{
return pcibios_enable_resources(dev);
}
void pcibios_align_resource(void *data, struct resource *res,
unsigned long size, unsigned long align)
{
struct pci_dev *dev = data;
if (res->flags & IORESOURCE_IO) {
unsigned long start = res->start;
/* We need to avoid collisions with `mirrored' VGA ports
and other strange ISA hardware, so we always want the
addresses kilobyte aligned. */
if (size > 0x100) {
printk(KERN_ERR "PCI: I/O Region %s/%d too large"
" (%ld bytes)\n", dev->slot_name,
dev->resource - res, size);
}
start = (start + 1024 - 1) & ~(1024 - 1);
res->start = start;
}
}
unsigned __init int pcibios_assign_all_busses(void)
{
return 1;
}
struct pci_fixup pcibios_fixups[] = { };
/*
* arch/mips/ddb5074/prom.c -- NEC DDB Vrc-5074 PROM routines
*
* Copyright (C) 2000 Geert Uytterhoeven <geert@sonycom.com>
* Sony Software Development Center Europe (SDCE), Brussels
*/
#include <linux/init.h>
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/bootmem.h>
#include <asm/addrspace.h>
#include <asm/bootinfo.h>
char arcs_cmdline[COMMAND_LINE_SIZE];
void __init prom_init(const char *s)
{
int i = 0;
if (s != (void *) -1)
while (*s && i < sizeof(arcs_cmdline) - 1)
arcs_cmdline[i++] = *s++;
arcs_cmdline[i] = '\0';
mips_machgroup = MACH_GROUP_NEC_DDB;
mips_machtype = MACH_NEC_DDB5074;
/* 64 MB non-upgradable */
add_memory_region(0, 64 << 20, BOOT_MEM_RAM);
}
void __init prom_free_prom_memory(void)
{
}
#
# Makefile for the NEC DDB Vrc-5074 specific kernel interface routines
# under Linux.
#
EXTRA_AFLAGS := $(CFLAGS)
obj-y += setup.o irq.o time.o prom.o pci.o \
int-handler.o nile4.o
obj-$(CONFIG_REMOTE_DEBUG) += dbg_io.o
/*
* arch/mips/ddb5074/int-handler.S -- NEC DDB Vrc-5074 interrupt handler
*
* Based on arch/mips/sgi/kernel/indyIRQ.S
*
* Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
*
* Copyright (C) 2000 Geert Uytterhoeven <geert@sonycom.com>
* Sony Software Development Center Europe (SDCE), Brussels
*/
#include <asm/asm.h>
#include <asm/mipsregs.h>
#include <asm/regdef.h>
#include <asm/stackframe.h>
/*
* A lot of complication here is taken away because:
*
* 1) We handle one interrupt and return, sitting in a loop and moving across
* all the pending IRQ bits in the cause register is _NOT_ the answer, the
* common case is one pending IRQ so optimize in that direction.
*
* 2) We need not check against bits in the status register IRQ mask, that
* would make this routine slow as hell.
*
* 3) Linux only thinks in terms of all IRQs on or all IRQs off, nothing in
* between like BSD spl() brain-damage.
*
* Furthermore, the IRQs on the INDY look basically (barring software IRQs
* which we don't use at all) like:
*
* MIPS IRQ Source
* -------- ------
* 0 Software (ignored)
* 1 Software (ignored)
* 2 Local IRQ level zero
* 3 Local IRQ level one
* 4 8254 Timer zero
* 5 8254 Timer one
* 6 Bus Error
* 7 R4k timer (what we use)
*
* We handle the IRQ according to _our_ priority which is:
*
* Highest ---- R4k Timer
* Local IRQ zero
* Local IRQ one
* Bus Error
* 8254 Timer zero
* Lowest ---- 8254 Timer one
*
* then we just return, if multiple IRQs are pending then we will just take
* another exception, big deal.
*/
.text
.set noreorder
.set noat
.align 5
NESTED(ddbIRQ, PT_SIZE, sp)
SAVE_ALL
CLI
.set at
mfc0 s1, CP0_CAUSE # get irq mask
#if 1
mfc0 t2,CP0_STATUS # get enabled interrupts
and s0, s1, t2 # isolate allowed ones
#endif
/* First we check for r4k counter/timer IRQ. */
andi a0, s0, CAUSEF_IP7 # cpu timer */
bnez a0, cpu_timer_irq
andi a0, s0, CAUSEF_IP2 # delay slot, check local level zero
beq a0, zero, 1f
andi a0, s0, CAUSEF_IP3 # delay slot, check local level one
/* Wheee, local level zero interrupt. */
jal ddb_local0_irqdispatch
move a0, sp # delay slot
j ret_from_irq
nop # delay slot
1:
beq a0, zero, 1f
andi a0, s0, CAUSEF_IP6 # delay slot, check bus error
/* Wheee, local level one interrupt. */
move a0, sp
jal ddb_local1_irqdispatch
nop
j ret_from_irq
nop
1:
beq a0, zero, 1f
nop
/* Wheee, an asynchronous bus error... */
move a0, sp
jal ddb_buserror_irq
nop
j ret_from_irq
nop
1:
/* Here by mistake? This is possible, what can happen
* is that by the time we take the exception the IRQ
* pin goes low, so just leave if this is the case.
*/
andi a0, s0, (CAUSEF_IP4 | CAUSEF_IP5)
beq a0, zero, 1f
/* Must be one of the 8254 timers... */
move a0, sp
jal ddb_8254timer_irq
nop
1:
/* phamtom interrupt */
move a0, s1
jal ddb_phantom_irq
nop
j ret_from_irq
nop
cpu_timer_irq:
li a0, 0
move a1, sp
jal do_IRQ
/* jal ll_timer_interrupt */
nop
j ret_from_irq
nop
END(ddbIRQ)
/*
* arch/mips/ddb5074/nile4.c -- NEC Vrc-5074 Nile 4 support routines
*
* Copyright (C) 2000 Geert Uytterhoeven <geert@sonycom.com>
* Sony Software Development Center Europe (SDCE), Brussels
*/
#include <linux/kernel.h>
#include <linux/types.h>
#include <asm/nile4.h>
/*
* Physical Device Address Registers
*
* Note: 32 bit addressing only!
*/
void nile4_set_pdar(u32 pdar, u32 phys, u32 size, int width,
int on_memory_bus, int visible)
{
u32 maskbits;
u32 widthbits;
if (pdar > NILE4_BOOTCS || (pdar & 7)) {
printk("nile4_set_pdar: invalid pdar %d\n", pdar);
return;
}
if (pdar == NILE4_INTCS && size != 0x00200000) {
printk("nile4_set_pdar: INTCS size must be 2 MB\n");
return;
}
switch (size) {
#if 0 /* We don't support 4 GB yet */
case 0x100000000: /* 4 GB */
maskbits = 4;
break;
#endif
case 0x80000000: /* 2 GB */
maskbits = 5;
break;
case 0x40000000: /* 1 GB */
maskbits = 6;
break;
case 0x20000000: /* 512 MB */
maskbits = 7;
break;
case 0x10000000: /* 256 MB */
maskbits = 8;
break;
case 0x08000000: /* 128 MB */
maskbits = 9;
break;
case 0x04000000: /* 64 MB */
maskbits = 10;
break;
case 0x02000000: /* 32 MB */
maskbits = 11;
break;
case 0x01000000: /* 16 MB */
maskbits = 12;
break;
case 0x00800000: /* 8 MB */
maskbits = 13;
break;
case 0x00400000: /* 4 MB */
maskbits = 14;
break;
case 0x00200000: /* 2 MB */
maskbits = 15;
break;
case 0: /* OFF */
maskbits = 0;
break;
default:
printk("nile4_set_pdar: unsupported size %p\n",
(void *) size);
return;
}
switch (width) {
case 8:
widthbits = 0;
break;
case 16:
widthbits = 1;
break;
case 32:
widthbits = 2;
break;
case 64:
widthbits = 3;
break;
default:
printk("nile4_set_pdar: unsupported width %d\n", width);
return;
}
nile4_out32(pdar, maskbits | (on_memory_bus ? 0x10 : 0) |
(visible ? 0x20 : 0) | (widthbits << 6) |
(phys & 0xffe00000));
nile4_out32(pdar + 4, 0);
/*
* When programming a PDAR, the register should be read immediately
* after writing it. This ensures that address decoders are properly
* configured.
*/
nile4_in32(pdar);
nile4_in32(pdar + 4);
}
/*
* PCI Master Registers
*
* Note: 32 bit addressing only!
*/
void nile4_set_pmr(u32 pmr, u32 type, u32 addr)
{
if (pmr != NILE4_PCIINIT0 && pmr != NILE4_PCIINIT1) {
printk("nile4_set_pmr: invalid pmr %d\n", pmr);
return;
}
switch (type) {
case NILE4_PCICMD_IACK: /* PCI Interrupt Acknowledge */
case NILE4_PCICMD_IO: /* PCI I/O Space */
case NILE4_PCICMD_MEM: /* PCI Memory Space */
case NILE4_PCICMD_CFG: /* PCI Configuration Space */
break;
default:
printk("nile4_set_pmr: invalid type %d\n", type);
return;
}
nile4_out32(pmr, (type << 1) | 0x10 | (addr & 0xffe00000));
nile4_out32(pmr + 4, 0);
}
/*
* Interrupt Programming
*/
void nile4_map_irq(int nile4_irq, int cpu_irq)
{
u32 offset, t;
offset = NILE4_INTCTRL;
if (nile4_irq >= 8) {
offset += 4;
nile4_irq -= 8;
}
t = nile4_in32(offset);
t &= ~(7 << (nile4_irq * 4));
t |= cpu_irq << (nile4_irq * 4);
nile4_out32(offset, t);
}
void nile4_map_irq_all(int cpu_irq)
{
u32 all, t;
all = cpu_irq;
all |= all << 4;
all |= all << 8;
all |= all << 16;
t = nile4_in32(NILE4_INTCTRL);
t &= 0x88888888;
t |= all;
nile4_out32(NILE4_INTCTRL, t);
t = nile4_in32(NILE4_INTCTRL + 4);
t &= 0x88888888;
t |= all;
nile4_out32(NILE4_INTCTRL + 4, t);
}
void nile4_enable_irq(int nile4_irq)
{
u32 offset, t;
offset = NILE4_INTCTRL;
if (nile4_irq >= 8) {
offset += 4;
nile4_irq -= 8;
}
t = nile4_in32(offset);
t |= 8 << (nile4_irq * 4);
nile4_out32(offset, t);
}
void nile4_disable_irq(int nile4_irq)
{
u32 offset, t;
offset = NILE4_INTCTRL;
if (nile4_irq >= 8) {
offset += 4;
nile4_irq -= 8;
}
t = nile4_in32(offset);
t &= ~(8 << (nile4_irq * 4));
nile4_out32(offset, t);
}
void nile4_disable_irq_all(void)
{
nile4_out32(NILE4_INTCTRL, 0);
nile4_out32(NILE4_INTCTRL + 4, 0);
}
u16 nile4_get_irq_stat(int cpu_irq)
{
return nile4_in16(NILE4_INTSTAT0 + cpu_irq * 2);
}
void nile4_enable_irq_output(int cpu_irq)
{
u32 t;
t = nile4_in32(NILE4_INTSTAT1 + 4);
t |= 1 << (16 + cpu_irq);
nile4_out32(NILE4_INTSTAT1, t);
}
void nile4_disable_irq_output(int cpu_irq)
{
u32 t;
t = nile4_in32(NILE4_INTSTAT1 + 4);
t &= ~(1 << (16 + cpu_irq));
nile4_out32(NILE4_INTSTAT1, t);
}
void nile4_set_pci_irq_polarity(int pci_irq, int high)
{
u32 t;
t = nile4_in32(NILE4_INTPPES);
if (high)
t &= ~(1 << (pci_irq * 2));
else
t |= 1 << (pci_irq * 2);
nile4_out32(NILE4_INTPPES, t);
}
void nile4_set_pci_irq_level_or_edge(int pci_irq, int level)
{
u32 t;
t = nile4_in32(NILE4_INTPPES);
if (level)
t |= 2 << (pci_irq * 2);
else
t &= ~(2 << (pci_irq * 2));
nile4_out32(NILE4_INTPPES, t);
}
void nile4_clear_irq(int nile4_irq)
{
nile4_out32(NILE4_INTCLR, 1 << nile4_irq);
}
void nile4_clear_irq_mask(u32 mask)
{
nile4_out32(NILE4_INTCLR, mask);
}
u8 nile4_i8259_iack(void)
{
u8 irq;
/* Set window 0 for interrupt acknowledge */
nile4_set_pmr(NILE4_PCIINIT0, NILE4_PCICMD_IACK, 0);
irq = *(volatile u8 *) NILE4_PCI_IACK_BASE;
/* Set window 0 for PCI I/O space */
nile4_set_pmr(NILE4_PCIINIT0, NILE4_PCICMD_IO, 0);
return irq;
}
#if 0
void nile4_dump_irq_status(void)
{
printk("CPUSTAT = %p:%p\n", (void *) nile4_in32(NILE4_CPUSTAT + 4),
(void *) nile4_in32(NILE4_CPUSTAT));
printk("INTCTRL = %p:%p\n", (void *) nile4_in32(NILE4_INTCTRL + 4),
(void *) nile4_in32(NILE4_INTCTRL));
printk("INTSTAT0 = %p:%p\n",
(void *) nile4_in32(NILE4_INTSTAT0 + 4),
(void *) nile4_in32(NILE4_INTSTAT0));
printk("INTSTAT1 = %p:%p\n",
(void *) nile4_in32(NILE4_INTSTAT1 + 4),
(void *) nile4_in32(NILE4_INTSTAT1));
printk("INTCLR = %p:%p\n", (void *) nile4_in32(NILE4_INTCLR + 4),
(void *) nile4_in32(NILE4_INTCLR));
printk("INTPPES = %p:%p\n", (void *) nile4_in32(NILE4_INTPPES + 4),
(void *) nile4_in32(NILE4_INTPPES));
}
#endif
This diff is collapsed.
/*
* arch/mips/ddb5476/prom.c -- NEC DDB Vrc-5476 PROM routines
*
* Copyright (C) 2000 Geert Uytterhoeven <geert@sonycom.com>
* Sony Software Development Center Europe (SDCE), Brussels
*
* Jun Sun - modified for DDB5476.
*/
#include <linux/init.h>
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/bootmem.h>
#include <asm/addrspace.h>
#include <asm/bootinfo.h>
char arcs_cmdline[COMMAND_LINE_SIZE];
/* [jsun@junsun.net] PMON passes arguments in C main() style */
void __init prom_init(int argc, const char **arg)
{
int i;
/* arg[0] is "g", the rest is boot parameters */
arcs_cmdline[0] = '\0';
for (i = 1; i < argc; i++) {
if (strlen(arcs_cmdline) + strlen(arg[i] + 1)
>= sizeof(arcs_cmdline))
break;
strcat(arcs_cmdline, arg[i]);
strcat(arcs_cmdline, " ");
}
mips_machgroup = MACH_GROUP_NEC_DDB;
mips_machtype = MACH_NEC_DDB5476;
/* 64 MB non-upgradable */
add_memory_region(0, 64 << 20, BOOT_MEM_RAM);
}
void __init prom_free_prom_memory(void)
{
}
/*
* arch/mips/ddb5074/time.c -- Timer routines
*
* Copyright (C) 2000 Geert Uytterhoeven <geert@sonycom.com>
* Sony Software Development Center Europe (SDCE), Brussels
*/
#include <linux/init.h>
#include <asm/mc146818rtc.h>
static unsigned char ddb_rtc_read_data(unsigned long addr)
{
outb_p(addr, RTC_PORT(0));
return inb_p(RTC_PORT(1));
}
static void ddb_rtc_write_data(unsigned char data, unsigned long addr)
{
outb_p(addr, RTC_PORT(0));
outb_p(data, RTC_PORT(1));
}
static int ddb_rtc_bcd_mode(void)
{
return 1;
}
struct rtc_ops ddb_rtc_ops = {
ddb_rtc_read_data,
ddb_rtc_write_data,
ddb_rtc_bcd_mode
};
......@@ -2,4 +2,4 @@
# Makefile for the common code of NEC DDB-Vrc5xxx board
#
obj-y += irq.o irq_cpu.o nile4.o prom.o pci.o pci_auto.o rtc_ds1386.o
obj-y += irq.o nile4.o prom.o rtc_ds1386.o
......@@ -13,12 +13,13 @@
*/
#include <linux/config.h>
#include <linux/init.h>
#include <asm/irq.h>
void (*irq_setup)(void);
void __init init_IRQ(void)
{
#ifdef CONFIG_REMOTE_DEBUG
#ifdef CONFIG_KGDB
extern void breakpoint(void);
extern void set_debug_traps(void);
......@@ -26,6 +27,8 @@ void __init init_IRQ(void)
set_debug_traps();
breakpoint();
#endif
/* set up default irq controller */
init_generic_irq();
/* invoke board-specific irq setup */
irq_setup();
......
/***********************************************************************
* Copyright 2001 MontaVista Software Inc.
* Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
*
* arch/mips/ddb5xxx/common/irq_cpu.c
* This file define the irq handler for MIPS CPU interrupts.
*
* 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.
***********************************************************************
*/
/*
* Almost all MIPS CPUs define 8 interrupt sources. They are typically
* level triggered (i.e., cannot be cleared from CPU; must be cleared from
* device). The first two are software interrupts. The last one is
* usually cpu timer interrupt if coutner register is present.
*
* This file exports one global function:
* mips_cpu_irq_init(u32 irq_base);
*/
#include <linux/irq.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <asm/mipsregs.h>
/* [jsun] sooner or later we should move this debug stuff to MIPS common */
#include <asm/ddb5xxx/debug.h>
static int mips_cpu_irq_base=-1;
static void
mips_cpu_irq_enable(unsigned int irq)
{
MIPS_ASSERT(mips_cpu_irq_base != -1);
MIPS_ASSERT(irq >= mips_cpu_irq_base);
MIPS_ASSERT(irq < mips_cpu_irq_base+8);
clear_cp0_cause( 1 << (irq - mips_cpu_irq_base + 8));
set_cp0_status(1 << (irq - mips_cpu_irq_base + 8));
}
static void
mips_cpu_irq_disable(unsigned int irq)
{
MIPS_ASSERT(mips_cpu_irq_base != -1);
MIPS_ASSERT(irq >= mips_cpu_irq_base);
MIPS_ASSERT(irq < mips_cpu_irq_base+8);
clear_cp0_status(1 << (irq - mips_cpu_irq_base + 8));
}
static unsigned int mips_cpu_irq_startup(unsigned int irq)
{
mips_cpu_irq_enable(irq);
return 0;
}
#define mips_cpu_irq_shutdown mips_cpu_irq_disable
static void
mips_cpu_irq_ack(unsigned int irq)
{
MIPS_ASSERT(mips_cpu_irq_base != -1);
MIPS_ASSERT(irq >= mips_cpu_irq_base);
MIPS_ASSERT(irq < mips_cpu_irq_base+8);
/* although we attemp to clear the IP bit in cause reigster, I think
* usually it is cleared by device (irq source)
*/
clear_cp0_cause( 1 << (irq - mips_cpu_irq_base + 8));
/* I am not fully convinced that I should disable irq here */
}
static void
mips_cpu_irq_end(unsigned int irq)
{
MIPS_ASSERT(mips_cpu_irq_base != -1);
MIPS_ASSERT(irq >= mips_cpu_irq_base);
MIPS_ASSERT(irq < mips_cpu_irq_base+8);
/* I am not fully convinced that I should enable irq here */
}
static hw_irq_controller mips_cpu_irq_controller = {
"CPU_irq",
mips_cpu_irq_startup,
mips_cpu_irq_shutdown,
mips_cpu_irq_enable,
mips_cpu_irq_disable,
mips_cpu_irq_ack,
mips_cpu_irq_end,
NULL /* no affinity stuff for UP */
};
void
mips_cpu_irq_init(u32 irq_base)
{
extern irq_desc_t irq_desc[];
u32 i;
for (i= irq_base; i< irq_base+8; i++) {
irq_desc[i].status = IRQ_DISABLED;
irq_desc[i].action = NULL;
irq_desc[i].depth = 1;
irq_desc[i].handler = &mips_cpu_irq_controller;
}
mips_cpu_irq_base = irq_base;
}
/***********************************************************************
/*
*
* Copyright 2001 MontaVista Software Inc.
* Author: jsun@mvista.com or jsun@junsun.net
......@@ -12,19 +12,14 @@
* 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/config.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <asm/ddb5xxx/ddb5xxx.h>
#include <asm/ddb5xxx/debug.h>
u32
ddb_calc_pdar(u32 phys, u32 size, int width,
ddb_calc_pdar(u32 phys, u32 size, int width,
int on_memory_bus, int pci_visible)
{
u32 maskbits;
......@@ -73,7 +68,7 @@ ddb_calc_pdar(u32 phys, u32 size, int width,
maskbits = 0;
break;
default:
panic("nile4_set_pdar: unsupported size %p\n", (void *) size);
panic("nile4_set_pdar: unsupported size %p", (void *) size);
}
switch (width) {
case 8:
......@@ -89,7 +84,7 @@ ddb_calc_pdar(u32 phys, u32 size, int width,
widthbits = 3;
break;
default:
panic("nile4_set_pdar: unsupported width %d\n", width);
panic("nile4_set_pdar: unsupported width %d", width);
}
return maskbits | (on_memory_bus ? 0x10 : 0) |
......@@ -128,7 +123,7 @@ void ddb_set_pmr(u32 pmr, u32 type, u32 addr, u32 options)
case DDB_PCICMD_CFG: /* PCI Configuration Space */
break;
default:
panic("nile4_set_pmr: invalid type %d\n", type);
panic("nile4_set_pmr: invalid type %d", type);
}
ddb_out32(pmr, (type << 1) | (addr & 0xffe00000) | options );
ddb_out32(pmr + 4, 0);
......
/***********************************************************************
* Copyright 2001 MontaVista Software Inc.
* Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
*
* arch/mips/ddb5xxx/common/pci.c
* Common PCI routines for DDB5xxx - as a matter of fact, meant for all
* MIPS machines.
*
* 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.
***********************************************************************
*/
/*
* This file contains common PCI routines meant to be shared for
* all MIPS machines.
*
* Strategies:
*
* . We rely on pci_auto.c file to assign PCI resources (MEM and IO)
* TODO: this should be optional for some machines where they do have
* a real "pcibios" that does resource assignment.
*
* . We then use pci_scan_bus() to "discover" all the resources for
* later use by Linux.
*
* . We finally reply on a board supplied function, pcibios_fixup_irq(), to
* to assign the interrupts. We may use setup-irq.c under drivers/pci
* later.
*
* . Specifically, we will *NOT* use pci_assign_unassigned_resources(),
* because we assume all PCI devices should have the resources correctly
* assigned and recorded.
*
* Limitations:
*
* . We "collapse" all IO and MEM spaces in sub-buses under a top-level bus
* into a contiguous range.
*
* . In the case of Memory space, the rnage is 1:1 mapping with CPU physical
* address space.
*
* . In the case of IO space, it starts from 0, and the beginning address
* is mapped to KSEG0ADDR(mips_io_port) in the CPU physical address.
*
* . These are the current MIPS limitations (by ioremap, etc). In the
* future, we may remove them.
*
* Credits:
* Most of the code are derived from the pci routines from PPC and Alpha,
* which were mostly writtne by
* Cort Dougan, cort@fsmlabs.com
* Matt Porter, mporter@mvista.com
* Dave Rusling david.rusling@reo.mts.dec.com
* David Mosberger davidm@cs.arizona.edu
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/pci.h>
#include <asm/ddb5xxx/pci.h>
#include <asm/ddb5xxx/debug.h>
struct pci_fixup pcibios_fixups[] = { {0} };
extern int pciauto_assign_resources(int busno, struct pci_channel * hose);
void __init pcibios_init(void)
{
struct pci_channel *p;
struct pci_bus *bus;
int busno;
/* assign resources */
busno=0;
for (p= mips_pci_channels; p->pci_ops != NULL; p++) {
busno = pciauto_assign_resources(busno, p) + 1;
}
/* scan the buses */
busno = 0;
for (p= mips_pci_channels; p->pci_ops != NULL; p++) {
bus = pci_scan_bus(busno, p->pci_ops, p);
busno = bus->subordinate+1;
}
/* fixup irqs (board specific routines) */
pcibios_fixup_irqs();
/*
* should we do a fixup of ioport_resource and iomem_resource
* based on mips_pci_channels?
* Let us wait and see if this is a common need and whether there
* are exceptions. Until then, each board should adjust them
* perhaps in their setup() function.
*/
}
int pcibios_enable_device(struct pci_dev *dev)
{
/* pciauto_assign_resources() will enable all devices found */
return 0;
}
unsigned long __init
pci_bridge_check_io(struct pci_dev *bridge)
{
u16 io;
pci_read_config_word(bridge, PCI_IO_BASE, &io);
if (!io) {
pci_write_config_word(bridge, PCI_IO_BASE, 0xf0f0);
pci_read_config_word(bridge, PCI_IO_BASE, &io);
pci_write_config_word(bridge, PCI_IO_BASE, 0x0);
}
if (io)
return IORESOURCE_IO;
printk(KERN_WARNING "PCI: bridge %s does not support I/O forwarding!\n",
bridge->name);
return 0;
}
void __init pcibios_fixup_bus(struct pci_bus *bus)
{
/* Propogate hose info into the subordinate devices. */
struct pci_channel *hose = bus->sysdata;
struct pci_dev *dev = bus->self;
if (!dev) {
/* Root bus */
bus->resource[0] = hose->io_resource;
bus->resource[1] = hose->mem_resource;
} else {
/* This is a bridge. Do not care how it's initialized,
just link its resources to the bus ones */
int i;
for(i=0; i<3; i++) {
bus->resource[i] =
&dev->resource[PCI_BRIDGE_RESOURCES+i];
bus->resource[i]->name = bus->name;
}
bus->resource[0]->flags |= pci_bridge_check_io(dev);
bus->resource[1]->flags |= IORESOURCE_MEM;
/* For now, propagate hose limits to the bus;
we'll adjust them later. */
bus->resource[0]->end = hose->io_resource->end;
bus->resource[1]->end = hose->mem_resource->end;
/* Turn off downstream PF memory address range by default */
bus->resource[2]->start = 1024*1024;
bus->resource[2]->end = bus->resource[2]->start - 1;
}
}
char *pcibios_setup(char *str)
{
return str;
}
void
pcibios_align_resource(void *data, struct resource *res,
unsigned long size, unsigned long align)
{
/* this should not be called */
MIPS_ASSERT(1 == 0);
}
This diff is collapsed.
......@@ -22,8 +22,21 @@
#include <asm/addrspace.h>
#include <asm/bootinfo.h>
#include <asm/ddb5xxx/ddb5xxx.h>
#include <asm/debug.h>
char arcs_cmdline[COMMAND_LINE_SIZE];
char arcs_cmdline[CL_SIZE];
const char *get_system_type(void)
{
switch (mips_machtype) {
case MACH_NEC_DDB5074: return "NEC DDB Vrc-5074";
case MACH_NEC_DDB5476: return "NEC DDB Vrc-5476";
case MACH_NEC_DDB5477: return "NEC DDB Vrc-5477";
case MACH_NEC_ROCKHOPPER: return "NEC Rockhopper";
case MACH_NEC_ROCKHOPPERII: return "NEC RockhopperII";
default: return "Unknown NEC board";
}
}
/* [jsun@junsun.net] PMON passes arguments in C main() style */
void __init prom_init(int argc, const char **arg)
......@@ -40,19 +53,91 @@ void __init prom_init(int argc, const char **arg)
strcat(arcs_cmdline, " ");
}
/* by default all these boards use dhcp/nfs root fs */
strcat(arcs_cmdline, "ip=bootp");
mips_machgroup = MACH_GROUP_NEC_DDB;
#if defined(CONFIG_DDB5074)
mips_machtype = MACH_NEC_DDB5074;
add_memory_region(0, DDB_SDRAM_SIZE, BOOT_MEM_RAM);
#elif defined(CONFIG_DDB5476)
mips_machtype = MACH_NEC_DDB5476;
add_memory_region(0, DDB_SDRAM_SIZE, BOOT_MEM_RAM);
#elif defined(CONFIG_DDB5477)
mips_machtype = MACH_NEC_DDB5477;
ddb5477_runtime_detection();
add_memory_region(0, board_ram_size, BOOT_MEM_RAM);
#endif
add_memory_region(0, DDB_SDRAM_SIZE, BOOT_MEM_RAM);
}
void __init prom_free_prom_memory(void)
{
}
#if defined(CONFIG_DDB5477)
#define DEFAULT_LCS1_BASE 0x19000000
#define TESTVAL1 'K'
#define TESTVAL2 'S'
int board_ram_size;
void ddb5477_runtime_detection(void)
{
volatile char *test_offset;
char saved_test_byte;
/* Determine if this is a DDB5477 board, or a BSB-VR0300
base board. We can tell by checking for the location of
the NVRAM. It lives at the beginning of LCS1 on the DDB5477,
and the beginning of LCS1 on the BSB-VR0300 is flash memory.
The first 2K of the NVRAM are reserved, so don't we'll poke
around just after that.
*/
/* We can only use the PCI bus to distinquish between
the Rockhopper and RockhopperII backplanes and this must
wait until ddb5477_board_init() in setup.c after the 5477
is initialized. So, until then handle
both Rockhopper and RockhopperII backplanes as Rockhopper 1
*/
test_offset = (char *)KSEG1ADDR(DEFAULT_LCS1_BASE + 0x800);
saved_test_byte = *test_offset;
*test_offset = TESTVAL1;
if (*test_offset != TESTVAL1) {
/* We couldn't set our test value, so it must not be NVRAM,
so it's a BSB_VR0300 */
mips_machtype = MACH_NEC_ROCKHOPPER;
} else {
/* We may have gotten lucky, and the TESTVAL1 was already
stored at the test location, so we must check a second
test value */
*test_offset = TESTVAL2;
if (*test_offset != TESTVAL2) {
/* OK, we couldn't set this value either, so it must
definately be a BSB_VR0300 */
mips_machtype = MACH_NEC_ROCKHOPPER;
} else {
/* We could change the value twice, so it must be
NVRAM, so it's a DDB_VRC5477 */
mips_machtype = MACH_NEC_DDB5477;
}
}
/* Restore the original byte */
*test_offset = saved_test_byte;
/* before we know a better way, we will trust PMON for getting
* RAM size
*/
board_ram_size = 1 << (36 - (ddb_in32(DDB_SDRAM0) & 0xf));
db_run(printk("DDB run-time detection : %s, %d MB RAM\n",
mips_machtype == MACH_NEC_DDB5477 ?
"DDB5477" : "Rockhopper",
board_ram_size >> 20));
/* we can't handle ram size > 128 MB */
db_assert(board_ram_size <= (128 << 20));
}
#endif
......@@ -25,7 +25,8 @@
#include <asm/time.h>
#include <asm/addrspace.h>
#include <asm/ddb5xxx/debug.h>
#include <asm/mc146818rtc.h>
#include <asm/debug.h>
#define EPOCH 2000
......@@ -36,7 +37,7 @@ static unsigned long rtc_base;
static unsigned long
rtc_ds1386_get_time(void)
{
{
u8 byte;
u8 temp;
unsigned int year, month, day, hour, minute, second;
......@@ -73,7 +74,7 @@ rtc_ds1386_get_time(void)
return mktime(year, month, day, hour, minute, second);
}
static int
static int
rtc_ds1386_set_time(unsigned long t)
{
struct rtc_time tm;
......@@ -89,6 +90,7 @@ rtc_ds1386_set_time(unsigned long t)
/* convert */
to_tm(t, &tm);
/* check each field one by one */
year = BIN2BCD(tm.tm_year - EPOCH);
if (year != READ_RTC(0xA)) {
......@@ -96,7 +98,7 @@ rtc_ds1386_set_time(unsigned long t)
}
temp = READ_RTC(0x9);
month = BIN2BCD(tm.tm_mon);
month = BIN2BCD(tm.tm_mon+1); /* tm_mon starts from 0 to 11 */
if (month != (temp & 0x1f)) {
WRITE_RTC( 0x9,
(month & 0x1f) | (temp & ~0x1f) );
......@@ -131,7 +133,7 @@ rtc_ds1386_set_time(unsigned long t)
if (second != READ_RTC(0x1)) {
WRITE_RTC(0x1, second);
}
return 0;
}
......@@ -139,10 +141,10 @@ void
rtc_ds1386_init(unsigned long base)
{
unsigned char byte;
/* remember the base */
rtc_base = base;
MIPS_ASSERT((rtc_base & 0xe0000000) == KSEG1);
db_assert((rtc_base & 0xe0000000) == KSEG1);
/* turn on RTC if it is not on */
byte = READ_RTC(0x9);
......
......@@ -3,6 +3,6 @@
# under Linux.
#
EXTRA_AFLAGS := $(CFLAGS)
obj-y += setup.o irq.o int-handler.o nile4_pic.o time.o
obj-y := setup.o irq.o time.o prom.o pci.o int-handler.o nile4.o
EXTRA_AFLAGS := $(CFLAGS)
......@@ -6,32 +6,25 @@
*/
#include <linux/config.h>
#include <linux/init.h>
#include <linux/irq.h>
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/types.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <asm/i8259.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/irq_cpu.h>
#include <asm/ptrace.h>
#include <asm/nile4.h>
#include <asm/ddb5074.h>
#include <asm/ddb5xxx/ddb5xxx.h>
#include <asm/ddb5xxx/ddb5074.h>
extern void __init i8259_init(void);
extern void i8259_disable_irq(unsigned int irq_nr);
extern void i8259_enable_irq(unsigned int irq_nr);
extern asmlinkage void ddbIRQ(void);
extern asmlinkage void i8259_do_irq(int irq, struct pt_regs *regs);
extern asmlinkage void do_IRQ(int irq, struct pt_regs *regs);
void no_action(int cpl, void *dev_id, struct pt_regs *regs)
{
}
static struct irqaction irq_cascade = { no_action, 0, 0, "cascade", NULL, NULL };
#define M1543_PNP_CONFIG 0x03f0 /* PnP Config Port */
#define M1543_PNP_INDEX 0x03f0 /* PnP Index Port */
......@@ -60,9 +53,9 @@ static void m1543_irq_setup(void)
*
* IRQ1 - keyboard (default set by M1543)
* IRQ3 - reserved for UART B (default set by M1543) (note that
* the schematics for the DDB Vrc-5074 board seem to
* indicate that IRQ3 is connected to the DS1386
* watchdog timer interrupt output so we might have
* the schematics for the DDB Vrc-5074 board seem to
* indicate that IRQ3 is connected to the DS1386
* watchdog timer interrupt output so we might have
* a conflict)
* IRQ4 - reserved for UART A (default set by M1543)
* IRQ5 - parallel (default set by M1543)
......@@ -71,7 +64,7 @@ static void m1543_irq_setup(void)
*/
/*
* Assing mouse interrupt to IRQ12
* Assing mouse interrupt to IRQ12
*/
/* Enter configuration mode */
......@@ -86,111 +79,44 @@ static void m1543_irq_setup(void)
outb(0x72, M1543_PNP_INDEX);
outb(0x0c, M1543_PNP_DATA);
/* Leave configration mode */
outb(0xbb, M1543_PNP_CONFIG);
/* Initialize the 8259 PIC in the M1543 */
i8259_init();
/* Enable the interrupt cascade */
nile4_enable_irq(NILE4_INT_INTE);
request_region(M1543_PNP_CONFIG, 2, "M1543 config");
request_region(M1543_INT1_MASTER_ELCR, 2, "pic ELCR");
}
static void nile4_irq_setup(void)
{
int i;
/* Map all interrupts to CPU int #0 */
nile4_map_irq_all(0);
/* PCI INTA#-E# must be level triggered */
nile4_set_pci_irq_level_or_edge(0, 1);
nile4_set_pci_irq_level_or_edge(1, 1);
nile4_set_pci_irq_level_or_edge(2, 1);
nile4_set_pci_irq_level_or_edge(3, 1);
nile4_set_pci_irq_level_or_edge(4, 1);
/* PCI INTA#-D# must be active low, INTE# must be active high */
nile4_set_pci_irq_polarity(0, 0);
nile4_set_pci_irq_polarity(1, 0);
nile4_set_pci_irq_polarity(2, 0);
nile4_set_pci_irq_polarity(3, 0);
nile4_set_pci_irq_polarity(4, 1);
outb(0x30, M1543_PNP_INDEX);
printk("device 7, 0x30: %02x\n",inb(M1543_PNP_DATA));
for (i = 0; i < 16; i++)
nile4_clear_irq(i);
/* Enable CPU int #0 */
nile4_enable_irq_output(0);
request_mem_region(NILE4_BASE, NILE4_SIZE, "Nile 4");
}
/*
* IRQ2 is cascade interrupt to second interrupt controller
*/
static struct irqaction irq2 = { no_action, 0, 0, "cascade", NULL, NULL };
outb(0x70, M1543_PNP_INDEX);
printk("device 7, 0x70: %02x\n",inb(M1543_PNP_DATA));
/* Leave configration mode */
outb(0xbb, M1543_PNP_CONFIG);
void disable_irq(unsigned int irq_nr)
{
if (is_i8259_irq(irq_nr))
i8259_disable_irq(irq_nr);
else
nile4_disable_irq(irq_to_nile4(irq_nr));
}
void enable_irq(unsigned int irq_nr)
{
if (is_i8259_irq(irq_nr))
i8259_enable_irq(irq_nr);
else
nile4_enable_irq(irq_to_nile4(irq_nr));
}
int table[16] = { 0, };
void ddb_local0_irqdispatch(struct pt_regs *regs)
{
u32 mask;
int nile4_irq;
#if 1
volatile static int nesting = 0;
if (nesting++ == 0)
ddb5074_led_d3(1);
ddb5074_led_hex(nesting < 16 ? nesting : 15);
#endif
mask = nile4_get_irq_stat(0);
nile4_clear_irq_mask(mask);
/* Handle the timer interrupt first */
#if 0
if (mask & (1 << NILE4_INT_GPT)) {
nile4_disable_irq(NILE4_INT_GPT);
do_IRQ(nile4_to_irq(NILE4_INT_GPT), regs);
nile4_enable_irq(NILE4_INT_GPT);
mask &= ~(1 << NILE4_INT_GPT);
}
#endif
for (nile4_irq = 0; mask; nile4_irq++, mask >>= 1)
if (mask & 1) {
nile4_disable_irq(nile4_irq);
if (nile4_irq == NILE4_INT_INTE) {
int i8259_irq = nile4_i8259_iack();
i8259_do_irq(i8259_irq, regs);
int i8259_irq;
nile4_clear_irq(NILE4_INT_INTE);
i8259_irq = nile4_i8259_iack();
do_IRQ(i8259_irq, regs);
} else
do_IRQ(nile4_to_irq(nile4_irq), regs);
nile4_enable_irq(nile4_irq);
}
#if 1
if (--nesting == 0)
ddb5074_led_d3(0);
ddb5074_led_hex(nesting < 16 ? nesting : 15);
#endif
}
void ddb_local1_irqdispatch(void)
......@@ -210,17 +136,33 @@ void ddb_8254timer_irq(void)
void __init ddb_irq_setup(void)
{
#ifdef CONFIG_REMOTE_DEBUG
#ifdef CONFIG_KGDB
if (remote_debug)
set_debug_traps();
breakpoint(); /* you may move this line to whereever you want :-) */
#endif
request_region(0x20, 0x20, "pic1");
request_region(0xa0, 0x20, "pic2");
i8259_setup_irq(2, &irq2);
nile4_irq_setup();
m1543_irq_setup();
/* setup cascade interrupts */
setup_irq(NILE4_IRQ_BASE + NILE4_INT_INTE, &irq_cascade);
setup_irq(CPU_IRQ_BASE + CPU_NILE4_CASCADE, &irq_cascade);
set_except_vector(0, ddbIRQ);
nile4_irq_setup(NILE4_IRQ_BASE);
m1543_irq_setup();
init_i8259_irqs();
printk("CPU_IRQ_BASE: %d\n",CPU_IRQ_BASE);
mips_cpu_irq_init(CPU_IRQ_BASE);
printk("enabling 8259 cascade\n");
ddb5074_led_hex(0);
/* Enable the interrupt cascade */
nile4_enable_irq(NILE4_IRQ_BASE+IRQ_I8259_CASCADE);
}
/*
* arch/mips/ddb5476/nile4.c --
* low-level PIC code for NEC Vrc-5476 (Nile 4)
*
* Copyright (C) 2000 Geert Uytterhoeven <geert@sonycom.com>
* Sony Software Development Center Europe (SDCE), Brussels
*
* Copyright 2001 MontaVista Software Inc.
* Author: jsun@mvista.com or jsun@junsun.net
*
*/
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <asm/addrspace.h>
#include <asm/ddb5xxx/ddb5xxx.h>
static int irq_base;
/*
* Interrupt Programming
*/
void nile4_map_irq(int nile4_irq, int cpu_irq)
{
u32 offset, t;
offset = DDB_INTCTRL;
if (nile4_irq >= 8) {
offset += 4;
nile4_irq -= 8;
}
t = ddb_in32(offset);
t &= ~(7 << (nile4_irq * 4));
t |= cpu_irq << (nile4_irq * 4);
ddb_out32(offset, t);
}
void nile4_map_irq_all(int cpu_irq)
{
u32 all, t;
all = cpu_irq;
all |= all << 4;
all |= all << 8;
all |= all << 16;
t = ddb_in32(DDB_INTCTRL);
t &= 0x88888888;
t |= all;
ddb_out32(DDB_INTCTRL, t);
t = ddb_in32(DDB_INTCTRL + 4);
t &= 0x88888888;
t |= all;
ddb_out32(DDB_INTCTRL + 4, t);
}
void nile4_enable_irq(unsigned int nile4_irq)
{
u32 offset, t;
nile4_irq-=irq_base;
ddb5074_led_hex(8);
offset = DDB_INTCTRL;
if (nile4_irq >= 8) {
offset += 4;
nile4_irq -= 8;
}
ddb5074_led_hex(9);
t = ddb_in32(offset);
ddb5074_led_hex(0xa);
t |= 8 << (nile4_irq * 4);
ddb_out32(offset, t);
ddb5074_led_hex(0xb);
}
void nile4_disable_irq(unsigned int nile4_irq)
{
u32 offset, t;
nile4_irq-=irq_base;
offset = DDB_INTCTRL;
if (nile4_irq >= 8) {
offset += 4;
nile4_irq -= 8;
}
t = ddb_in32(offset);
t &= ~(8 << (nile4_irq * 4));
ddb_out32(offset, t);
}
void nile4_disable_irq_all(void)
{
ddb_out32(DDB_INTCTRL, 0);
ddb_out32(DDB_INTCTRL + 4, 0);
}
u16 nile4_get_irq_stat(int cpu_irq)
{
return ddb_in16(DDB_INTSTAT0 + cpu_irq * 2);
}
void nile4_enable_irq_output(int cpu_irq)
{
u32 t;
t = ddb_in32(DDB_INTSTAT1 + 4);
t |= 1 << (16 + cpu_irq);
ddb_out32(DDB_INTSTAT1, t);
}
void nile4_disable_irq_output(int cpu_irq)
{
u32 t;
t = ddb_in32(DDB_INTSTAT1 + 4);
t &= ~(1 << (16 + cpu_irq));
ddb_out32(DDB_INTSTAT1, t);
}
void nile4_set_pci_irq_polarity(int pci_irq, int high)
{
u32 t;
t = ddb_in32(DDB_INTPPES);
if (high)
t &= ~(1 << (pci_irq * 2));
else
t |= 1 << (pci_irq * 2);
ddb_out32(DDB_INTPPES, t);
}
void nile4_set_pci_irq_level_or_edge(int pci_irq, int level)
{
u32 t;
t = ddb_in32(DDB_INTPPES);
if (level)
t |= 2 << (pci_irq * 2);
else
t &= ~(2 << (pci_irq * 2));
ddb_out32(DDB_INTPPES, t);
}
void nile4_clear_irq(int nile4_irq)
{
nile4_irq-=irq_base;
ddb_out32(DDB_INTCLR, 1 << nile4_irq);
}
void nile4_clear_irq_mask(u32 mask)
{
ddb_out32(DDB_INTCLR, mask);
}
u8 nile4_i8259_iack(void)
{
u8 irq;
u32 reg;
/* Set window 0 for interrupt acknowledge */
reg = ddb_in32(DDB_PCIINIT0);
ddb_set_pmr(DDB_PCIINIT0, DDB_PCICMD_IACK, 0, DDB_PCI_ACCESS_32);
irq = *(volatile u8 *) KSEG1ADDR(DDB_PCI_IACK_BASE);
/* restore window 0 for PCI I/O space */
// ddb_set_pmr(DDB_PCIINIT0, DDB_PCICMD_IO, 0, DDB_PCI_ACCESS_32);
ddb_out32(DDB_PCIINIT0, reg);
/* i8269.c set the base vector to be 0x0 */
return irq ;
}
static unsigned int nile4_irq_startup(unsigned int irq) {
nile4_enable_irq(irq);
return 0;
}
static void nile4_ack_irq(unsigned int irq) {
ddb5074_led_hex(4);
nile4_clear_irq(irq);
ddb5074_led_hex(2);
nile4_disable_irq(irq);
ddb5074_led_hex(0);
}
static void nile4_irq_end(unsigned int irq) {
ddb5074_led_hex(3);
if(!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) {
ddb5074_led_hex(5);
nile4_enable_irq(irq);
ddb5074_led_hex(7);
}
ddb5074_led_hex(1);
}
#define nile4_irq_shutdown nile4_disable_irq
static hw_irq_controller nile4_irq_controller = {
"nile4",
nile4_irq_startup,
nile4_irq_shutdown,
nile4_enable_irq,
nile4_disable_irq,
nile4_ack_irq,
nile4_irq_end,
NULL
};
void nile4_irq_setup(u32 base) {
int i;
extern irq_desc_t irq_desc[];
irq_base=base;
/* Map all interrupts to CPU int #0 */
nile4_map_irq_all(0);
/* PCI INTA#-E# must be level triggered */
nile4_set_pci_irq_level_or_edge(0, 1);
nile4_set_pci_irq_level_or_edge(1, 1);
nile4_set_pci_irq_level_or_edge(2, 1);
nile4_set_pci_irq_level_or_edge(3, 1);
nile4_set_pci_irq_level_or_edge(4, 1);
/* PCI INTA#-D# must be active low, INTE# must be active high */
nile4_set_pci_irq_polarity(0, 0);
nile4_set_pci_irq_polarity(1, 0);
nile4_set_pci_irq_polarity(2, 0);
nile4_set_pci_irq_polarity(3, 0);
nile4_set_pci_irq_polarity(4, 1);
for (i = 0; i < 16; i++) {
nile4_clear_irq(i);
nile4_disable_irq(i);
}
/* Enable CPU int #0 */
nile4_enable_irq_output(0);
for (i= base; i< base + NUM_NILE4_INTERRUPTS; i++) {
irq_desc[i].status = IRQ_DISABLED;
irq_desc[i].action = NULL;
irq_desc[i].depth = 1;
irq_desc[i].handler = &nile4_irq_controller;
}
}
#if defined(CONFIG_RUNTIME_DEBUG)
void nile4_dump_irq_status(void)
{
printk(KERN_DEBUG "
CPUSTAT = %p:%p\n", (void *) ddb_in32(DDB_CPUSTAT + 4),
(void *) ddb_in32(DDB_CPUSTAT));
printk(KERN_DEBUG "
INTCTRL = %p:%p\n", (void *) ddb_in32(DDB_INTCTRL + 4),
(void *) ddb_in32(DDB_INTCTRL));
printk(KERN_DEBUG
"INTSTAT0 = %p:%p\n",
(void *) ddb_in32(DDB_INTSTAT0 + 4),
(void *) ddb_in32(DDB_INTSTAT0));
printk(KERN_DEBUG
"INTSTAT1 = %p:%p\n",
(void *) ddb_in32(DDB_INTSTAT1 + 4),
(void *) ddb_in32(DDB_INTSTAT1));
printk(KERN_DEBUG
"INTCLR = %p:%p\n", (void *) ddb_in32(DDB_INTCLR + 4),
(void *) ddb_in32(DDB_INTCLR));
printk(KERN_DEBUG
"INTPPES = %p:%p\n", (void *) ddb_in32(DDB_INTPPES + 4),
(void *) ddb_in32(DDB_INTPPES));
}
#endif
......@@ -13,21 +13,23 @@
#include <linux/console.h>
#include <linux/sched.h>
#include <linux/mc146818rtc.h>
#include <linux/pc_keyb.h>
#include <linux/pci.h>
#include <linux/ide.h>
#include <linux/ioport.h>
#include <linux/irq.h>
#include <asm/addrspace.h>
#include <asm/bcache.h>
#include <asm/keyboard.h>
#include <asm/irq.h>
#include <asm/reboot.h>
#include <asm/gdb-stub.h>
#include <asm/time.h>
#include <asm/nile4.h>
#include <asm/ddb5074.h>
#include <asm/ddb5xxx/ddb5074.h>
#include <asm/ddb5xxx/ddb5xxx.h>
#ifdef CONFIG_REMOTE_DEBUG
#ifdef CONFIG_KGDB
extern void rs_kgdb_hook(int);
extern void breakpoint(void);
#endif
......@@ -37,6 +39,7 @@ extern void console_setup(char *);
#endif
extern struct ide_ops std_ide_ops;
extern struct kbd_ops std_kbd_ops;
extern struct rtc_ops ddb_rtc_ops;
static void (*back_to_prom) (void) = (void (*)(void)) 0xbfc00000;
......@@ -72,11 +75,11 @@ static void ddb_machine_power_off(void)
}
extern void ddb_irq_setup(void);
extern void rtc_ds1386_init(unsigned long base);
void (*board_time_init) (struct irqaction * irq);
extern void (*board_timer_setup) (struct irqaction * irq);
static void __init ddb_time_init(struct irqaction *irq)
static void __init ddb_timer_init(struct irqaction *irq)
{
/* set the clock to 1 Hz */
nile4_out32(NILE4_T2CTRL, 1000000);
......@@ -85,26 +88,32 @@ static void __init ddb_time_init(struct irqaction *irq)
/* reset timer */
nile4_out32(NILE4_T2CNTR, 0);
/* enable interrupt */
nile4_enable_irq(NILE4_INT_GPT);
i8259_setup_irq(nile4_to_irq(NILE4_INT_GPT), irq);
change_cp0_status(ST0_IM,
setup_irq(nile4_to_irq(NILE4_INT_GPT), irq);
nile4_enable_irq(nile4_to_irq(NILE4_INT_GPT));
change_c0_status(ST0_IM,
IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4);
}
static void __init ddb_time_init(void)
{
/* we have ds1396 RTC chip */
rtc_ds1386_init(KSEG1ADDR(DDB_PCI_MEM_BASE));
}
void __init ddb_setup(void)
{
extern int panic_timeout;
irq_setup = ddb_irq_setup;
mips_io_port_base = NILE4_PCI_IO_BASE;
set_io_port_base(NILE4_PCI_IO_BASE);
isa_slot_offset = NILE4_PCI_MEM_BASE;
request_region(0x00, 0x20, "dma1");
request_region(0x40, 0x20, "timer");
request_region(0x70, 0x10, "rtc");
request_region(0x80, 0x10, "dma page reg");
request_region(0xc0, 0x20, "dma2");
board_timer_setup = ddb_timer_init;
board_time_init = ddb_time_init;
_machine_restart = ddb_machine_restart;
_machine_halt = ddb_machine_halt;
_machine_power_off = ddb_machine_power_off;
......@@ -112,8 +121,18 @@ void __init ddb_setup(void)
#ifdef CONFIG_BLK_DEV_IDE
ide_ops = &std_ide_ops;
#endif
rtc_ops = &ddb_rtc_ops;
ddb_out32(DDB_BAR0, 0);
ddb_set_pmr(DDB_PCIINIT0, DDB_PCICMD_IO, 0, 0x10);
ddb_set_pmr(DDB_PCIINIT1, DDB_PCICMD_MEM, DDB_PCI_MEM_BASE , 0x10);
#ifdef CONFIG_FB
conswitchp = &dummy_con;
#endif
/* Reboot on panic */
panic_timeout = 180;
}
......
......@@ -3,21 +3,22 @@
*
* Copyright (C) 2000 Geert Uytterhoeven <geert@sonycom.com>
* Sony Software Development Center Europe (SDCE), Brussels
*
*/
#include <linux/init.h>
#include <asm/mc146818rtc.h>
#include <asm/ddb5xxx/ddb5074.h>
#include <asm/ddb5xxx/ddb5xxx.h>
static unsigned char ddb_rtc_read_data(unsigned long addr)
{
outb_p(addr, RTC_PORT(0));
return inb_p(RTC_PORT(1));
return *(volatile unsigned char *)(KSEG1ADDR(DDB_PCI_MEM_BASE)+addr);
}
static void ddb_rtc_write_data(unsigned char data, unsigned long addr)
{
outb_p(addr, RTC_PORT(0));
outb_p(data, RTC_PORT(1));
*(volatile unsigned char *)(KSEG1ADDR(DDB_PCI_MEM_BASE)+addr)=data;
}
static int ddb_rtc_bcd_mode(void)
......
#
# Makefile for the NEC DDB Vrc-5476 specific kernel interface routines
# under Linux.
#
obj-y += setup.o irq.o int-handler.o nile4_pic.o vrc5476_irq.o
obj-$(CONFIG_KGDB) += dbg_io.o
EXTRA_AFLAGS := $(CFLAGS)
/*
* kgdb io functions for DDB5476. We use the second serial port.
*
* Copyright (C) 2001 MontaVista Software Inc.
* Author: jsun@mvista.com or jsun@junsun.net
*
* 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.
*
*/
/* ======================= CONFIG ======================== */
#include <linux/config.h>
/* [jsun] we use the second serial port for kdb */
#define BASE 0xa60002f8
#define MAX_BAUD 115200
/* distance in bytes between two serial registers */
#define REG_OFFSET 1
#if (defined(CONFIG_DDB5476) && defined(CONFIG_REMOTE_DEBUG))
/*
* 0 - kgdb does serial init
* 1 - kgdb skip serial init
*/
static int remoteDebugInitialized = 0;
/*
* the default baud rate *if* kgdb does serial init
*/
#define BAUD_DEFAULT UART16550_BAUD_38400
/* --- CONFIG --- */
/* ======================= END OF CONFIG ======================== */
/* we need uint32 uint8 */
/* #include "types.h" */
typedef unsigned char uint8;
typedef unsigned int uint32;
/* --- END OF CONFIG --- */
#define UART16550_BAUD_2400 2400
#define UART16550_BAUD_4800 4800
#define UART16550_BAUD_9600 9600
......@@ -34,33 +58,23 @@ typedef unsigned int uint32;
#define UART16550_STOP_1BIT 0x0
#define UART16550_STOP_2BIT 0x4
/* ----------------------------------------------------- */
/* === CONFIG === */
/* [jsun] we use the second serial port for kdb */
#define BASE 0xa60002f8
#define MAX_BAUD 115200
/* === END OF CONFIG === */
/* register offset */
#define OFS_RCV_BUFFER 0
#define OFS_TRANS_HOLD 0
#define OFS_SEND_BUFFER 0
#define OFS_INTR_ENABLE 1
#define OFS_INTR_ID 2
#define OFS_DATA_FORMAT 3
#define OFS_LINE_CONTROL 3
#define OFS_MODEM_CONTROL 4
#define OFS_RS232_OUTPUT 4
#define OFS_LINE_STATUS 5
#define OFS_MODEM_STATUS 6
#define OFS_RS232_INPUT 6
#define OFS_SCRATCH_PAD 7
#define OFS_INTR_ENABLE (1*REG_OFFSET)
#define OFS_INTR_ID (2*REG_OFFSET)
#define OFS_DATA_FORMAT (3*REG_OFFSET)
#define OFS_LINE_CONTROL (3*REG_OFFSET)
#define OFS_MODEM_CONTROL (4*REG_OFFSET)
#define OFS_RS232_OUTPUT (4*REG_OFFSET)
#define OFS_LINE_STATUS (5*REG_OFFSET)
#define OFS_MODEM_STATUS (6*REG_OFFSET)
#define OFS_RS232_INPUT (6*REG_OFFSET)
#define OFS_SCRATCH_PAD (7*REG_OFFSET)
#define OFS_DIVISOR_LSB 0
#define OFS_DIVISOR_MSB 1
#define OFS_DIVISOR_LSB (0*REG_OFFSET)
#define OFS_DIVISOR_MSB (1*REG_OFFSET)
/* memory-mapped read/write of the port */
......@@ -69,57 +83,54 @@ typedef unsigned int uint32;
void debugInit(uint32 baud, uint8 data, uint8 parity, uint8 stop)
{
/* disable interrupts */
UART16550_WRITE(OFS_INTR_ENABLE, 0);
/* disable interrupts */
UART16550_WRITE(OFS_INTR_ENABLE, 0);
/* set up buad rate */
{
uint32 divisor;
/* set up buad rate */
{
uint32 divisor;
/* set DIAB bit */
UART16550_WRITE(OFS_LINE_CONTROL, 0x80);
/* set DIAB bit */
UART16550_WRITE(OFS_LINE_CONTROL, 0x80);
/* set divisor */
divisor = MAX_BAUD / baud;
UART16550_WRITE(OFS_DIVISOR_LSB, divisor & 0xff);
UART16550_WRITE(OFS_DIVISOR_MSB, (divisor & 0xff00) >> 8);
/* set divisor */
divisor = MAX_BAUD / baud;
UART16550_WRITE(OFS_DIVISOR_LSB, divisor & 0xff);
UART16550_WRITE(OFS_DIVISOR_MSB, (divisor & 0xff00) >> 8);
/* clear DIAB bit */
UART16550_WRITE(OFS_LINE_CONTROL, 0x0);
}
/* clear DIAB bit */
UART16550_WRITE(OFS_LINE_CONTROL, 0x0);
}
/* set data format */
UART16550_WRITE(OFS_DATA_FORMAT, data | parity | stop);
/* set data format */
UART16550_WRITE(OFS_DATA_FORMAT, data | parity | stop);
}
static int remoteDebugInitialized = 0;
uint8 getDebugChar(void)
{
if (!remoteDebugInitialized) {
remoteDebugInitialized = 1;
debugInit(UART16550_BAUD_38400,
UART16550_DATA_8BIT,
UART16550_PARITY_NONE, UART16550_STOP_1BIT);
}
while ((UART16550_READ(OFS_LINE_STATUS) & 0x1) == 0);
return UART16550_READ(OFS_RCV_BUFFER);
if (!remoteDebugInitialized) {
remoteDebugInitialized = 1;
debugInit(BAUD_DEFAULT,
UART16550_DATA_8BIT,
UART16550_PARITY_NONE, UART16550_STOP_1BIT);
}
while ((UART16550_READ(OFS_LINE_STATUS) & 0x1) == 0);
return UART16550_READ(OFS_RCV_BUFFER);
}
int putDebugChar(uint8 byte)
{
if (!remoteDebugInitialized) {
remoteDebugInitialized = 1;
debugInit(UART16550_BAUD_9600,
UART16550_DATA_8BIT,
UART16550_PARITY_NONE, UART16550_STOP_1BIT);
}
while ((UART16550_READ(OFS_LINE_STATUS) & 0x20) == 0);
UART16550_WRITE(OFS_SEND_BUFFER, byte);
return 1;
if (!remoteDebugInitialized) {
remoteDebugInitialized = 1;
debugInit(BAUD_DEFAULT,
UART16550_DATA_8BIT,
UART16550_PARITY_NONE, UART16550_STOP_1BIT);
}
while ((UART16550_READ(OFS_LINE_STATUS) & 0x20) == 0);
UART16550_WRITE(OFS_SEND_BUFFER, byte);
return 1;
}
#endif
/*
* Copyright 2001 MontaVista Software Inc.
* Author: jsun@mvista.com or jsun@junsun.net
*
* First-level interrupt dispatcher for ddb5476
*
* 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/mipsregs.h>
#include <asm/addrspace.h>
#include <asm/regdef.h>
#include <asm/stackframe.h>
#include <asm/ddb5xxx/ddb5476.h>
/*
* first level interrupt dispatcher for ocelot board -
* We check for the timer first, then check PCI ints A and D.
* Then check for serial IRQ and fall through.
*/
.align 5
NESTED(ddb5476_handle_int, PT_SIZE, sp)
SAVE_ALL
CLI
.set at
.set noreorder
mfc0 t0, CP0_CAUSE
mfc0 t2, CP0_STATUS
and t0, t2
andi t1, t0, STATUSF_IP7 /* cpu timer */
bnez t1, ll_cpu_ip7
andi t1, t0, STATUSF_IP2 /* vrc5476 & i8259 */
bnez t1, ll_cpu_ip2
andi t1, t0, STATUSF_IP3
bnez t1, ll_cpu_ip3
andi t1, t0, STATUSF_IP4
bnez t1, ll_cpu_ip4
andi t1, t0, STATUSF_IP5
bnez t1, ll_cpu_ip5
andi t1, t0, STATUSF_IP6
bnez t1, ll_cpu_ip6
andi t1, t0, STATUSF_IP0 /* software int 0 */
bnez t1, ll_cpu_ip0
andi t1, t0, STATUSF_IP1 /* software int 1 */
bnez t1, ll_cpu_ip1
nop
.set reorder
/* wrong alarm or masked ... */
// j spurious_interrupt
move a0, sp
jal vrc5476_irq_dispatch
j ret_from_irq
nop
.align 5
ll_cpu_ip0:
li a0, CPU_IRQ_BASE + 0
move a1, sp
jal do_IRQ
j ret_from_irq
ll_cpu_ip1:
li a0, CPU_IRQ_BASE + 1
move a1, sp
jal do_IRQ
j ret_from_irq
ll_cpu_ip2: /* jump to second-level dispatching */
move a0, sp
jal vrc5476_irq_dispatch
j ret_from_irq
ll_cpu_ip3:
li a0, CPU_IRQ_BASE + 3
move a1, sp
jal do_IRQ
j ret_from_irq
ll_cpu_ip4:
li a0, CPU_IRQ_BASE + 4
move a1, sp
jal do_IRQ
j ret_from_irq
ll_cpu_ip5:
li a0, CPU_IRQ_BASE + 5
move a1, sp
jal do_IRQ
j ret_from_irq
ll_cpu_ip6:
li a0, CPU_IRQ_BASE + 6
move a1, sp
jal do_IRQ
j ret_from_irq
ll_cpu_ip7:
li a0, CPU_IRQ_BASE + 7
move a1, sp
jal do_IRQ
j ret_from_irq
END(ddb5476_handle_int)
......@@ -3,33 +3,22 @@
*
* Copyright (C) 2000 Geert Uytterhoeven <geert@sonycom.com>
* Sony Software Development Center Europe (SDCE), Brussels
*
* Re-write the whole thing to use new irq.c file.
* Copyright (C) 2001 MontaVista Software Inc.
* Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
*
*/
#include <linux/config.h>
#include <linux/init.h>
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/types.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <asm/i8259.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/ptrace.h>
#include <asm/nile4.h>
extern void __init i8259_init(void);
extern void i8259_disable_irq(unsigned int irq_nr);
extern void i8259_enable_irq(unsigned int irq_nr);
extern asmlinkage void ddbIRQ(void);
extern asmlinkage void i8259_do_irq(int irq, struct pt_regs *regs);
extern asmlinkage void do_IRQ(int irq, struct pt_regs *regs);
void no_action(int cpl, void *dev_id, struct pt_regs *regs)
{
}
#include <asm/ddb5xxx/ddb5xxx.h>
#define M1543_PNP_CONFIG 0x03f0 /* PnP Config Port */
#define M1543_PNP_INDEX 0x03f0 /* PnP Index Port */
......@@ -48,16 +37,6 @@ void no_action(int cpl, void *dev_id, struct pt_regs *regs)
#define M1543_INT1_MASTER_ELCR 0x04d0 /* INT_1 (master) Edge/Level Control */
#define M1543_INT1_SLAVE_ELCR 0x04d1 /* INT_1 (slave) Edge/Level Control */
static struct {
struct resource m1543_config;
struct resource pic_elcr;
} m1543_ioport = {
{ "M1543 config", M1543_PNP_CONFIG, M1543_PNP_CONFIG + 1,
IORESOURCE_BUSY},
{ "pic ELCR", M1543_INT1_MASTER_ELCR, M1543_INT1_MASTER_ELCR + 1,
IORESOURCE_BUSY}
};
static void m1543_irq_setup(void)
{
/*
......@@ -67,9 +46,9 @@ static void m1543_irq_setup(void)
*
* IRQ1 - keyboard (default set by M1543)
* IRQ3 - reserved for UART B (default set by M1543) (note that
* the schematics for the DDB Vrc-5476 board seem to
* indicate that IRQ3 is connected to the DS1386
* watchdog timer interrupt output so we might have
* the schematics for the DDB Vrc-5476 board seem to
* indicate that IRQ3 is connected to the DS1386
* watchdog timer interrupt output so we might have
* a conflict)
* IRQ4 - reserved for UART A (default set by M1543)
* IRQ5 - parallel (default set by M1543)
......@@ -81,7 +60,7 @@ static void m1543_irq_setup(void)
*/
/*
* Assing mouse interrupt to IRQ12
* Assing mouse interrupt to IRQ12
*/
/* Enter configuration mode */
......@@ -98,27 +77,13 @@ static void m1543_irq_setup(void)
/* Leave configration mode */
outb(0xbb, M1543_PNP_CONFIG);
/* Initialize the 8259 PIC in the M1543 */
i8259_init();
/* Enable the interrupt cascade from M1543 */
nile4_enable_irq(NILE4_INT_INTC);
/* request io ports */
if (request_resource(&ioport_resource, &m1543_ioport.m1543_config)
|| request_resource(&ioport_resource, &m1543_ioport.pic_elcr)) {
printk("m1543_irq_setup : requesting io ports failed.\n");
for (;;);
}
}
static void nile4_irq_setup(void)
{
int i;
/* Map all interrupts to CPU int #0 */
/* Map all interrupts to CPU int #0 (IP2) */
nile4_map_irq_all(0);
/* PCI INTA#-E# must be level triggered */
......@@ -142,110 +107,37 @@ static void nile4_irq_setup(void)
/* memory resource acquire in ddb_setup */
}
static struct irqaction irq_cascade = { no_action, 0, 0, "cascade", NULL, NULL };
static struct irqaction irq_error = { no_action, 0, 0, "error", NULL, NULL };
/*
* IRQ2 is cascade interrupt to second interrupt controller
*/
static struct irqaction irq2 = { no_action, 0, 0, "cascade", NULL, NULL };
void disable_irq(unsigned int irq_nr)
{
if (is_i8259_irq(irq_nr))
i8259_disable_irq(irq_nr);
else
nile4_disable_irq(irq_to_nile4(irq_nr));
}
void enable_irq(unsigned int irq_nr)
{
if (is_i8259_irq(irq_nr))
i8259_enable_irq(irq_nr);
else
nile4_enable_irq(irq_to_nile4(irq_nr));
}
int table[16] = { 0, };
void ddb_local0_irqdispatch(struct pt_regs *regs)
{
u32 mask;
int nile4_irq;
#if 0
volatile static int nesting = 0;
if (nesting++ == 0)
ddb5476_led_d3(1);
ddb5476_led_hex(nesting < 16 ? nesting : 15);
#endif
mask = nile4_get_irq_stat(0);
nile4_clear_irq_mask(mask);
/* Handle the timer interrupt first */
if (mask & (1 << NILE4_INT_GPT)) {
nile4_disable_irq(NILE4_INT_GPT);
do_IRQ(nile4_to_irq(NILE4_INT_GPT), regs);
nile4_enable_irq(NILE4_INT_GPT);
mask &= ~(1 << NILE4_INT_GPT);
}
for (nile4_irq = 0; mask; nile4_irq++, mask >>= 1)
if (mask & 1) {
nile4_disable_irq(nile4_irq);
if (nile4_irq == NILE4_INT_INTC) {
int i8259_irq = nile4_i8259_iack();
i8259_do_irq(i8259_irq, regs);
} else {
do_IRQ(nile4_to_irq(nile4_irq), regs);
}
nile4_enable_irq(nile4_irq);
}
#if 0
if (--nesting == 0)
ddb5476_led_d3(0);
ddb5476_led_hex(nesting < 16 ? nesting : 15);
#endif
}
void ddb_local1_irqdispatch(void)
{
printk("ddb_local1_irqdispatch called\n");
}
void ddb_buserror_irq(void)
{
printk("ddb_buserror_irq called\n");
}
void ddb_8254timer_irq(void)
{
printk("ddb_8254timer_irq called\n");
}
void ddb_phantom_irq(unsigned long cause)
{
printk("phantom interrupts detected : \n");
printk("\tcause \t\t0x%08x\n", cause);
printk("\tcause reg\t0x%08x\n",
read_32bit_cp0_register(CP0_CAUSE));
printk("\tstatus reg\t0x%08x\n",
read_32bit_cp0_register(CP0_STATUS));
}
extern asmlinkage void ddb5476_handle_int(void);
extern int setup_irq(unsigned int irq, struct irqaction *irqaction);
extern void mips_cpu_irq_init(u32 irq_base);
extern void vrc5476_irq_init(u32 irq_base);
void __init ddb_irq_setup(void)
void __init ddb5476_irq_setup(void)
{
#ifdef CONFIG_REMOTE_DEBUG
printk("Wait for gdb client connection ...\n");
set_debug_traps();
breakpoint(); /* you may move this line to whereever you want :-) */
#endif
i8259_setup_irq(2, &irq2);
/* hardware initialization */
nile4_irq_setup();
m1543_irq_setup();
/* we pin #0 - #4 (no internal timer) */
change_cp0_status(ST0_IM,
IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4);
set_except_vector(0, ddbIRQ);
/* controller setup */
init_i8259_irqs();
vrc5476_irq_init(VRC5476_IRQ_BASE);
mips_cpu_irq_init(CPU_IRQ_BASE);
/* setup cascade interrupts */
setup_irq(VRC5476_IRQ_BASE + VRC5476_I8259_CASCADE, &irq_cascade);
setup_irq(CPU_IRQ_BASE + CPU_VRC5476_CASCADE, &irq_cascade);
/* setup error interrupts for debugging */
setup_irq(VRC5476_IRQ_BASE + VRC5476_IRQ_CPCE, &irq_error);
setup_irq(VRC5476_IRQ_BASE + VRC5476_IRQ_CNTD, &irq_error);
setup_irq(VRC5476_IRQ_BASE + VRC5476_IRQ_MCE, &irq_error);
setup_irq(VRC5476_IRQ_BASE + VRC5476_IRQ_LBRT, &irq_error);
setup_irq(VRC5476_IRQ_BASE + VRC5476_IRQ_PCIS, &irq_error);
setup_irq(VRC5476_IRQ_BASE + VRC5476_IRQ_PCI, &irq_error);
/* setup the grandpa intr vector */
set_except_vector(0, ddb5476_handle_int);
}
/*
* arch/mips/ddb5476/nile4.c --
* low-level PIC code for NEC Vrc-5476 (Nile 4)
*
* Copyright (C) 2000 Geert Uytterhoeven <geert@sonycom.com>
* Sony Software Development Center Europe (SDCE), Brussels
*
* Copyright 2001 MontaVista Software Inc.
* Author: jsun@mvista.com or jsun@junsun.net
*
*/
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <asm/addrspace.h>
#include <asm/ddb5xxx/ddb5xxx.h>
/*
* Interrupt Programming
*/
void nile4_map_irq(int nile4_irq, int cpu_irq)
{
u32 offset, t;
offset = DDB_INTCTRL;
if (nile4_irq >= 8) {
offset += 4;
nile4_irq -= 8;
}
t = ddb_in32(offset);
t &= ~(7 << (nile4_irq * 4));
t |= cpu_irq << (nile4_irq * 4);
ddb_out32(offset, t);
}
void nile4_map_irq_all(int cpu_irq)
{
u32 all, t;
all = cpu_irq;
all |= all << 4;
all |= all << 8;
all |= all << 16;
t = ddb_in32(DDB_INTCTRL);
t &= 0x88888888;
t |= all;
ddb_out32(DDB_INTCTRL, t);
t = ddb_in32(DDB_INTCTRL + 4);
t &= 0x88888888;
t |= all;
ddb_out32(DDB_INTCTRL + 4, t);
}
void nile4_enable_irq(int nile4_irq)
{
u32 offset, t;
offset = DDB_INTCTRL;
if (nile4_irq >= 8) {
offset += 4;
nile4_irq -= 8;
}
t = ddb_in32(offset);
t |= 8 << (nile4_irq * 4);
ddb_out32(offset, t);
}
void nile4_disable_irq(int nile4_irq)
{
u32 offset, t;
offset = DDB_INTCTRL;
if (nile4_irq >= 8) {
offset += 4;
nile4_irq -= 8;
}
t = ddb_in32(offset);
t &= ~(8 << (nile4_irq * 4));
ddb_out32(offset, t);
}
void nile4_disable_irq_all(void)
{
ddb_out32(DDB_INTCTRL, 0);
ddb_out32(DDB_INTCTRL + 4, 0);
}
u16 nile4_get_irq_stat(int cpu_irq)
{
return ddb_in16(DDB_INTSTAT0 + cpu_irq * 2);
}
void nile4_enable_irq_output(int cpu_irq)
{
u32 t;
t = ddb_in32(DDB_INTSTAT1 + 4);
t |= 1 << (16 + cpu_irq);
ddb_out32(DDB_INTSTAT1, t);
}
void nile4_disable_irq_output(int cpu_irq)
{
u32 t;
t = ddb_in32(DDB_INTSTAT1 + 4);
t &= ~(1 << (16 + cpu_irq));
ddb_out32(DDB_INTSTAT1, t);
}
void nile4_set_pci_irq_polarity(int pci_irq, int high)
{
u32 t;
t = ddb_in32(DDB_INTPPES);
if (high)
t &= ~(1 << (pci_irq * 2));
else
t |= 1 << (pci_irq * 2);
ddb_out32(DDB_INTPPES, t);
}
void nile4_set_pci_irq_level_or_edge(int pci_irq, int level)
{
u32 t;
t = ddb_in32(DDB_INTPPES);
if (level)
t |= 2 << (pci_irq * 2);
else
t &= ~(2 << (pci_irq * 2));
ddb_out32(DDB_INTPPES, t);
}
void nile4_clear_irq(int nile4_irq)
{
ddb_out32(DDB_INTCLR, 1 << nile4_irq);
}
void nile4_clear_irq_mask(u32 mask)
{
ddb_out32(DDB_INTCLR, mask);
}
u8 nile4_i8259_iack(void)
{
u8 irq;
u32 reg;
/* Set window 0 for interrupt acknowledge */
reg = ddb_in32(DDB_PCIINIT0);
ddb_set_pmr(DDB_PCIINIT0, DDB_PCICMD_IACK, 0, DDB_PCI_ACCESS_32);
irq = *(volatile u8 *) KSEG1ADDR(DDB_PCI_IACK_BASE);
/* restore window 0 for PCI I/O space */
// ddb_set_pmr(DDB_PCIINIT0, DDB_PCICMD_IO, 0, DDB_PCI_ACCESS_32);
ddb_out32(DDB_PCIINIT0, reg);
/* i8269.c set the base vector to be 0x0 */
return irq + I8259_IRQ_BASE;
}
#if defined(CONFIG_RUNTIME_DEBUG)
void nile4_dump_irq_status(void)
{
printk(KERN_DEBUG "
CPUSTAT = %p:%p\n", (void *) ddb_in32(DDB_CPUSTAT + 4),
(void *) ddb_in32(DDB_CPUSTAT));
printk(KERN_DEBUG "
INTCTRL = %p:%p\n", (void *) ddb_in32(DDB_INTCTRL + 4),
(void *) ddb_in32(DDB_INTCTRL));
printk(KERN_DEBUG
"INTSTAT0 = %p:%p\n",
(void *) ddb_in32(DDB_INTSTAT0 + 4),
(void *) ddb_in32(DDB_INTSTAT0));
printk(KERN_DEBUG
"INTSTAT1 = %p:%p\n",
(void *) ddb_in32(DDB_INTSTAT1 + 4),
(void *) ddb_in32(DDB_INTSTAT1));
printk(KERN_DEBUG
"INTCLR = %p:%p\n", (void *) ddb_in32(DDB_INTCLR + 4),
(void *) ddb_in32(DDB_INTCLR));
printk(KERN_DEBUG
"INTPPES = %p:%p\n", (void *) ddb_in32(DDB_INTPPES + 4),
(void *) ddb_in32(DDB_INTPPES));
}
#endif
/*
* The irq controller for vrc5476.
*
* Copyright (C) 2001 MontaVista Software Inc.
* Author: jsun@mvista.com or jsun@junsun.net
*
* 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/interrupt.h>
#include <linux/irq.h>
#include <linux/types.h>
#include <linux/ptrace.h>
#include <asm/system.h>
#include <asm/ddb5xxx/ddb5xxx.h>
static int irq_base;
static void vrc5476_irq_enable(uint irq)
{
nile4_enable_irq(irq - irq_base);
}
static void vrc5476_irq_disable(uint irq)
{
nile4_disable_irq(irq - irq_base);
}
static unsigned int vrc5476_irq_startup(uint irq)
{
nile4_enable_irq(irq - irq_base);
return 0;
}
#define vrc5476_irq_shutdown vrc5476_irq_disable
static void vrc5476_irq_ack(uint irq)
{
nile4_clear_irq(irq - irq_base);
nile4_disable_irq(irq - irq_base);
}
static void vrc5476_irq_end(uint irq)
{
if(!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
vrc5476_irq_enable(irq);
}
static hw_irq_controller vrc5476_irq_controller = {
"vrc5476",
vrc5476_irq_startup,
vrc5476_irq_shutdown,
vrc5476_irq_enable,
vrc5476_irq_disable,
vrc5476_irq_ack,
vrc5476_irq_end,
NULL /* no affinity stuff for UP */
};
void __init
vrc5476_irq_init(u32 base)
{
extern irq_desc_t irq_desc[];
u32 i;
irq_base = base;
for (i= base; i< base + NUM_VRC5476_IRQ; i++) {
irq_desc[i].status = IRQ_DISABLED;
irq_desc[i].action = NULL;
irq_desc[i].depth = 1;
irq_desc[i].handler = &vrc5476_irq_controller;
}
}
asmlinkage void
vrc5476_irq_dispatch(struct pt_regs *regs)
{
extern void spurious_interrupt(void);
u32 mask;
int nile4_irq;
mask = nile4_get_irq_stat(0);
/* quick check for possible time interrupt */
if (mask & (1 << VRC5476_IRQ_GPT)) {
do_IRQ(VRC5476_IRQ_BASE + VRC5476_IRQ_GPT, regs);
return;
}
/* check for i8259 interrupts */
if (mask & (1 << VRC5476_I8259_CASCADE)) {
int i8259_irq = nile4_i8259_iack();
do_IRQ(I8259_IRQ_BASE + i8259_irq, regs);
return;
}
/* regular nile4 interrupts (we should not really have any */
for (nile4_irq = 0; mask; nile4_irq++, mask >>= 1) {
if (mask & 1) {
do_IRQ(VRC5476_IRQ_BASE + nile4_irq, regs);
return;
}
}
spurious_interrupt();
}
......@@ -2,10 +2,9 @@
# Makefile for NEC DDB-Vrc5477 board
#
EXTRA_AFLAGS := $(CFLAGS)
obj-y += int-handler.o irq.o irq_5477.o setup.o lcd44780.o
obj-y += int-handler.o irq.o irq_5477.o setup.o pci.o pci_ops.o
obj-$(CONFIG_RUNTIME_DEBUG) += debug.o
obj-$(CONFIG_KGDB) += kgdb_io.o
obj-$(CONFIG_LL_DEBUG) += debug.o
obj-$(CONFIG_REMOTE_DEBUG) += kgdb_io.o
obj-$(CONFIG_BLK_DEV_INITRD) += ramdisk.o
EXTRA_AFLAGS := $(CFLAGS)
......@@ -15,8 +15,6 @@
*/
#include <linux/kernel.h>
#include <linux/interrupt.h>
#include <linux/signal.h> /* SA_INTERRUPT */
#include <asm/mipsregs.h>
#include <asm/ddb5xxx/ddb5xxx.h>
......@@ -32,9 +30,9 @@ void jsun_show_regs(char *name, Register *regs)
printk("\nshow regs: %s\n", name);
for(i=0;regs[i].regname!= NULL; i++) {
printk("%-16s= %08x\t\t(@%08x)\n",
regs[i].regname,
*(unsigned *)(regs[i].regaddr),
printk("%-16s= %08x\t\t(@%08x)\n",
regs[i].regname,
*(unsigned *)(regs[i].regaddr),
regs[i].regaddr);
}
}
......@@ -58,15 +56,15 @@ static Register int_regs[] = {
void vrc5477_show_int_regs()
{
jsun_show_regs("interrupt registers", int_regs);
printk("CPU CAUSE = %08x\n", read_32bit_cp0_register(CP0_CAUSE));
printk("CPU STATUS = %08x\n", read_32bit_cp0_register(CP0_STATUS));
printk("CPU CAUSE = %08x\n", read_c0_cause());
printk("CPU STATUS = %08x\n", read_c0_status());
}
static Register pdar_regs[] = {
{"DDB_SDRAM0", DDB_BASE + DDB_SDRAM0},
{"DDB_SDRAM1", DDB_BASE + DDB_SDRAM1},
{"DDB_LDCS0", DDB_BASE + DDB_LDCS0},
{"DDB_LDCS1", DDB_BASE + DDB_LDCS1},
{"DDB_LDCS2", DDB_BASE + DDB_LDCS2},
{"DDB_LCS0", DDB_BASE + DDB_LCS0},
{"DDB_LCS1", DDB_BASE + DDB_LCS1},
{"DDB_LCS2", DDB_BASE + DDB_LCS2},
{"DDB_INTCS", DDB_BASE + DDB_INTCS},
{"DDB_BOOTCS", DDB_BASE + DDB_BOOTCS},
{"DDB_PCIW0", DDB_BASE + DDB_PCIW0},
......
......@@ -9,13 +9,12 @@
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#include <linux/config.h>
#include <asm/asm.h>
#include <asm/mipsregs.h>
#include <asm/addrspace.h>
#include <asm/regdef.h>
#include <asm/stackframe.h>
#include <asm/ddb5xxx/ddb5477.h>
/*
* first level interrupt dispatcher for ocelot board -
......@@ -28,14 +27,14 @@
CLI
.set at
.set noreorder
mfc0 t0, CP0_CAUSE
mfc0 t0, CP0_CAUSE
mfc0 t2, CP0_STATUS
and t0, t2
andi t1, t0, STATUSF_IP7 /* cpu timer */
bnez t1, ll_cputimer_irq
andi t1, t0, (STATUSF_IP2 | STATUSF_IP3 | STATUSF_IP4 | STATUSF_IP5 | STATUSF_IP6 )
andi t1, t0, (STATUSF_IP2 | STATUSF_IP3 | STATUSF_IP4 | STATUSF_IP5 | STATUSF_IP6 )
bnez t1, ll_vrc5477_irq
andi t1, t0, STATUSF_IP0 /* software int 0 */
bnez t1, ll_cpu_ip0
......@@ -51,26 +50,26 @@
.align 5
ll_vrc5477_irq:
ll_vrc5477_irq:
move a0, sp
jal vrc5477_irq_dispatch
j ret_from_irq
ll_cputimer_irq:
li a0, 7
li a0, CPU_IRQ_BASE + 7
move a1, sp
jal do_IRQ
j ret_from_irq
ll_cpu_ip0:
li a0, 0
ll_cpu_ip0:
li a0, CPU_IRQ_BASE + 0
move a1, sp
jal do_IRQ
j ret_from_irq
ll_cpu_ip1:
li a0, 1
ll_cpu_ip1:
li a0, CPU_IRQ_BASE + 1
move a1, sp
jal do_IRQ
j ret_from_irq
......@@ -12,16 +12,20 @@
*/
#include <linux/config.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/types.h>
#include <linux/ptrace.h>
#include <asm/i8259.h>
#include <asm/system.h>
#include <asm/mipsregs.h>
#include <asm/debug.h>
#include <asm/addrspace.h>
#include <asm/bootinfo.h>
#include <asm/ddb5xxx/ddb5xxx.h>
/* [jsun] sooner or later we should move this debug stuff to MIPS common */
#include <asm/ddb5xxx/debug.h>
/*
* IRQ mapping
......@@ -37,7 +41,7 @@
* 7 - cpu timer (used by default)
*
* 8-39: 32 Vrc5477 interrupt sources
* (refer to the Vrc5477 manual)
* (refer to the Vrc5477 manual)
*/
#define PCI0 DDB_INTPPES0
......@@ -55,7 +59,7 @@
#define INTD 3
#define INTE 4
static inline void
static inline void
set_pci_int_attr(u32 pci, u32 intn, u32 active, u32 trigger)
{
u32 reg_value;
......@@ -63,7 +67,7 @@ set_pci_int_attr(u32 pci, u32 intn, u32 active, u32 trigger)
reg_value = ddb_in32(pci);
reg_bitmask = 0x3 << (intn * 2);
reg_value &= ~reg_bitmask;
reg_value |= (active | trigger) << (intn * 2);
ddb_out32(pci, reg_value);
......@@ -72,26 +76,31 @@ set_pci_int_attr(u32 pci, u32 intn, u32 active, u32 trigger)
extern void vrc5477_irq_init(u32 base);
extern void mips_cpu_irq_init(u32 base);
extern asmlinkage void ddb5477_handle_int(void);
extern int setup_irq(unsigned int irq, struct irqaction *irqaction);
static struct irqaction irq_cascade = { no_action, 0, 0, "cascade", NULL, NULL };
void
ddb5477_irq_setup(void)
{
MIPS_DEBUG(printk("ddb5477_irq_setup invoked.\n"));
db_run(printk("ddb5477_irq_setup invoked.\n"));
/* by default, we disable all interrupts and route all vrc5477
/* by default, we disable all interrupts and route all vrc5477
* interrupts to pin 0 (irq 2) */
ddb_out32(DDB_INTCTRL0, 0);
ddb_out32(DDB_INTCTRL1, 0);
ddb_out32(DDB_INTCTRL2, 0);
ddb_out32(DDB_INTCTRL3, 0);
clear_cp0_status(0xff00);
set_cp0_status(0x0400);
clear_c0_status(0xff00);
set_c0_status(0x0400);
/* setup PCI interrupt attributes */
set_pci_int_attr(PCI0, INTA, ACTIVE_LOW, LEVEL_SENSE);
set_pci_int_attr(PCI0, INTB, ACTIVE_LOW, LEVEL_SENSE);
set_pci_int_attr(PCI0, INTC, ACTIVE_LOW, LEVEL_SENSE);
if (mips_machtype == MACH_NEC_ROCKHOPPERII)
set_pci_int_attr(PCI0, INTC, ACTIVE_HIGH, LEVEL_SENSE);
else
set_pci_int_attr(PCI0, INTC, ACTIVE_LOW, LEVEL_SENSE);
set_pci_int_attr(PCI0, INTD, ACTIVE_LOW, LEVEL_SENSE);
set_pci_int_attr(PCI0, INTE, ACTIVE_LOW, LEVEL_SENSE);
......@@ -101,9 +110,9 @@ ddb5477_irq_setup(void)
set_pci_int_attr(PCI1, INTD, ACTIVE_LOW, LEVEL_SENSE);
set_pci_int_attr(PCI1, INTE, ACTIVE_LOW, LEVEL_SENSE);
/*
/*
* for debugging purpose, we enable several error interrupts
* and route them to pin 1. (IP3)
* and route them to pin 1. (IP3)
*/
/* cpu parity check - 0 */
ll_vrc5477_irq_route(0, 1); ll_vrc5477_irq_enable(0);
......@@ -121,13 +130,34 @@ ddb5477_irq_setup(void)
ll_vrc5477_irq_route(31, 1); ll_vrc5477_irq_enable(31);
/* init all controllers */
mips_cpu_irq_init(0);
vrc5477_irq_init(8);
init_i8259_irqs();
mips_cpu_irq_init(CPU_IRQ_BASE);
vrc5477_irq_init(VRC5477_IRQ_BASE);
/* setup cascade interrupts */
setup_irq(VRC5477_IRQ_BASE + VRC5477_I8259_CASCADE, &irq_cascade);
setup_irq(CPU_IRQ_BASE + CPU_VRC5477_CASCADE, &irq_cascade);
/* hook up the first-level interrupt handler */
set_except_vector(0, ddb5477_handle_int);
}
u8 i8259_interrupt_ack(void)
{
u8 irq;
u32 reg;
/* Set window 0 for interrupt acknowledge */
reg = ddb_in32(DDB_PCIINIT10);
ddb_set_pmr(DDB_PCIINIT10, DDB_PCICMD_IACK, 0, DDB_PCI_ACCESS_32);
irq = *(volatile u8 *) KSEG1ADDR(DDB_PCI_IACK_BASE);
ddb_out32(DDB_PCIINIT10, reg);
/* i8259.c set the base vector to be 0x0 */
return irq + I8259_IRQ_BASE;
}
/*
* the first level int-handler will jump here if it is a vrc5477 irq
*/
......@@ -135,29 +165,38 @@ ddb5477_irq_setup(void)
asmlinkage void
vrc5477_irq_dispatch(struct pt_regs *regs)
{
extern unsigned int do_IRQ(int irq, struct pt_regs *regs);
u32 intStatus;
u32 bitmask;
u32 i;
MIPS_ASSERT(ddb_in32(DDB_INT2STAT) == 0);
MIPS_ASSERT(ddb_in32(DDB_INT3STAT) == 0);
MIPS_ASSERT(ddb_in32(DDB_INT4STAT) == 0);
MIPS_ASSERT(ddb_in32(DDB_NMISTAT) == 0);
db_assert(ddb_in32(DDB_INT2STAT) == 0);
db_assert(ddb_in32(DDB_INT3STAT) == 0);
db_assert(ddb_in32(DDB_INT4STAT) == 0);
db_assert(ddb_in32(DDB_NMISTAT) == 0);
if (ddb_in32(DDB_INT1STAT) != 0) {
#if defined(CONFIG_LL_DEBUG)
#if defined(CONFIG_RUNTIME_DEBUG)
vrc5477_show_int_regs();
#endif
panic("error interrupt has happened.\n");
panic("error interrupt has happened.");
}
intStatus = ddb_in32(DDB_INT0STAT);
if (mips_machtype == MACH_NEC_ROCKHOPPERII) {
/* check for i8259 interrupts */
if (intStatus & (1 << VRC5477_I8259_CASCADE)) {
int i8259_irq = i8259_interrupt_ack();
do_IRQ(I8259_IRQ_BASE + i8259_irq, regs);
return;
}
}
for (i=0, bitmask=1; i<= NUM_5477_IRQS; bitmask <<=1, i++) {
/* do we need to "and" with the int mask? */
if (intStatus & bitmask) {
do_IRQ(8 + i, regs);
do_IRQ(VRC5477_IRQ_BASE + i, regs);
return;
}
}
}
/***********************************************************************
/*
* Copyright 2001 MontaVista Software Inc.
* Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
*
......@@ -9,7 +9,7 @@
* 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.
***********************************************************************
*
*/
/*
......@@ -19,37 +19,36 @@
* vrc5477_irq_init(u32 irq_base);
*/
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/types.h>
#include <linux/ptrace.h>
#include <asm/ddb5xxx/ddb5xxx.h>
#include <asm/debug.h>
/* [jsun] sooner or later we should move this debug stuff to MIPS common */
#include <asm/ddb5xxx/debug.h>
#include <asm/ddb5xxx/ddb5xxx.h>
/* number of total irqs supported by Vrc5477 */
#define NUM_5477_IRQ 32
static int vrc5477_irq_base=-1;
static int vrc5477_irq_base = -1;
static void
static void
vrc5477_irq_enable(unsigned int irq)
{
MIPS_ASSERT(vrc5477_irq_base != -1);
MIPS_ASSERT(irq >= vrc5477_irq_base);
MIPS_ASSERT(irq < vrc5477_irq_base+ NUM_5477_IRQ);
db_assert(vrc5477_irq_base != -1);
db_assert(irq >= vrc5477_irq_base);
db_assert(irq < vrc5477_irq_base+ NUM_5477_IRQ);
ll_vrc5477_irq_enable(irq - vrc5477_irq_base);
}
static void
static void
vrc5477_irq_disable(unsigned int irq)
{
MIPS_ASSERT(vrc5477_irq_base != -1);
MIPS_ASSERT(irq >= vrc5477_irq_base);
MIPS_ASSERT(irq < vrc5477_irq_base + NUM_5477_IRQ);
db_assert(vrc5477_irq_base != -1);
db_assert(irq >= vrc5477_irq_base);
db_assert(irq < vrc5477_irq_base + NUM_5477_IRQ);
ll_vrc5477_irq_disable(irq - vrc5477_irq_base);
}
......@@ -65,9 +64,9 @@ static unsigned int vrc5477_irq_startup(unsigned int irq)
static void
vrc5477_irq_ack(unsigned int irq)
{
MIPS_ASSERT(vrc5477_irq_base != -1);
MIPS_ASSERT(irq >= vrc5477_irq_base);
MIPS_ASSERT(irq < vrc5477_irq_base+ NUM_5477_IRQ);
db_assert(vrc5477_irq_base != -1);
db_assert(irq >= vrc5477_irq_base);
db_assert(irq < vrc5477_irq_base+ NUM_5477_IRQ);
/* clear the interrupt bit */
/* some irqs require the driver to clear the sources */
......@@ -82,11 +81,12 @@ vrc5477_irq_ack(unsigned int irq)
static void
vrc5477_irq_end(unsigned int irq)
{
MIPS_ASSERT(vrc5477_irq_base != -1);
MIPS_ASSERT(irq >= vrc5477_irq_base);
MIPS_ASSERT(irq < vrc5477_irq_base + NUM_5477_IRQ);
db_assert(vrc5477_irq_base != -1);
db_assert(irq >= vrc5477_irq_base);
db_assert(irq < vrc5477_irq_base + NUM_5477_IRQ);
ll_vrc5477_irq_enable( irq - vrc5477_irq_base);
if(!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
ll_vrc5477_irq_enable( irq - vrc5477_irq_base);
}
hw_irq_controller vrc5477_irq_controller = {
......@@ -100,7 +100,7 @@ hw_irq_controller vrc5477_irq_controller = {
NULL /* no affinity stuff for UP */
};
void
void
vrc5477_irq_init(u32 irq_base)
{
extern irq_desc_t irq_desc[];
......@@ -112,17 +112,8 @@ vrc5477_irq_init(u32 irq_base)
irq_desc[i].depth = 1;
irq_desc[i].handler = &vrc5477_irq_controller;
}
vrc5477_irq_base = irq_base;
}
int vrc5477_irq_to_irq(int irq)
{
MIPS_ASSERT(irq >= 0);
MIPS_ASSERT(irq < NUM_5477_IRQ);
return irq + vrc5477_irq_base;
vrc5477_irq_base = irq_base;
}
void ll_vrc5477_irq_route(int vrc5477_irq, int ip)
......@@ -131,10 +122,10 @@ void ll_vrc5477_irq_route(int vrc5477_irq, int ip)
u32 reg_bitmask;
u32 reg_index;
MIPS_ASSERT(vrc5477_irq >= 0);
MIPS_ASSERT(vrc5477_irq < NUM_5477_IRQ);
MIPS_ASSERT(ip >= 0);
MIPS_ASSERT((ip < 5) || (ip == 6));
db_assert(vrc5477_irq >= 0);
db_assert(vrc5477_irq < NUM_5477_IRQ);
db_assert(ip >= 0);
db_assert((ip < 5) || (ip == 6));
reg_index = DDB_INTCTRL0 + vrc5477_irq/8*4;
reg_value = ddb_in32(reg_index);
......@@ -150,13 +141,13 @@ void ll_vrc5477_irq_enable(int vrc5477_irq)
u32 reg_bitmask;
u32 reg_index;
MIPS_ASSERT(vrc5477_irq >= 0);
MIPS_ASSERT(vrc5477_irq < NUM_5477_IRQ);
db_assert(vrc5477_irq >= 0);
db_assert(vrc5477_irq < NUM_5477_IRQ);
reg_index = DDB_INTCTRL0 + vrc5477_irq/8*4;
reg_value = ddb_in32(reg_index);
reg_bitmask = 8 << (vrc5477_irq % 8 * 4);
MIPS_ASSERT((reg_value & reg_bitmask) == 0);
db_assert((reg_value & reg_bitmask) == 0);
ddb_out32(reg_index, reg_value | reg_bitmask);
}
......@@ -166,14 +157,14 @@ void ll_vrc5477_irq_disable(int vrc5477_irq)
u32 reg_bitmask;
u32 reg_index;
MIPS_ASSERT(vrc5477_irq >= 0);
MIPS_ASSERT(vrc5477_irq < NUM_5477_IRQ);
db_assert(vrc5477_irq >= 0);
db_assert(vrc5477_irq < NUM_5477_IRQ);
reg_index = DDB_INTCTRL0 + vrc5477_irq/8*4;
reg_value = ddb_in32(reg_index);
reg_bitmask = 8 << (vrc5477_irq % 8 * 4);
/* we assert that the interrupt is enabled (perhaps over-zealous) */
MIPS_ASSERT( (reg_value & reg_bitmask) != 0);
db_assert( (reg_value & reg_bitmask) != 0);
ddb_out32(reg_index, reg_value & ~reg_bitmask);
}
This diff is collapsed.
This diff is collapsed.
/*
* lcd44780.h
* Simple "driver" for a memory-mapped 44780-style LCD display.
*
* Copyright 2001 Bradley D. LaRonde <brad@ltc.com>
*
* 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.
*
*/
void lcd44780_puts(const char* s);
void lcd44780_init(void);
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
/*
* include/asm-mips/ddb5074.h -- NEC DDB Vrc-5074 definitions
*
* Copyright (C) 2000 Geert Uytterhoeven <geert@sonycom.com>
* Sony Software Development Center Europe (SDCE), Brussels
*/
#ifndef _ASM_DDB5XXX_DDB5074_H
#define _ASM_DDB5XXX_DDB5074_H
#include <asm/nile4.h>
#define DDB_SDRAM_SIZE 0x04000000 /* 64MB */
#define DDB_PCI_IO_BASE 0x06000000
#define DDB_PCI_IO_SIZE 0x02000000 /* 32 MB */
#define DDB_PCI_MEM_BASE 0x08000000
#define DDB_PCI_MEM_SIZE 0x08000000 /* 128 MB */
#define DDB_PCI_CONFIG_BASE DDB_PCI_MEM_BASE
#define DDB_PCI_CONFIG_SIZE DDB_PCI_MEM_SIZE
#define NILE4_PCI_IO_BASE 0xa6000000
#define NILE4_PCI_MEM_BASE 0xa8000000
#define NILE4_PCI_CFG_BASE NILE4_PCI_MEM_BASE
#define DDB_PCI_IACK_BASE NILE4_PCI_IO_BASE
#define NILE4_IRQ_BASE NUM_I8259_INTERRUPTS
#define CPU_IRQ_BASE (NUM_NILE4_INTERRUPTS + NILE4_IRQ_BASE)
#define CPU_NILE4_CASCADE 2
extern void ddb5074_led_hex(int hex);
extern void ddb5074_led_d2(int on);
extern void ddb5074_led_d3(int on);
extern void nile4_irq_setup(u32 base);
#endif
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