Update of /cvsroot/linux-mips/linux/arch/mips/ddb5xxx/ddb5476 In directory usw-pr-cvs1:/tmp/cvs-serv16561/arch/mips/ddb5xxx/ddb5476 Added Files: Makefile dbg_io.c int-handler.S irq.c nile4_pic.c pci.c pci_ops.c setup.c vrc5476_irq.c Log Message: Update DDB5476 and sync up with oss tree. --- NEW FILE: Makefile --- # # Makefile for the NEC DDB Vrc-5476 specific kernel interface routines # under Linux. # # Note! Dependencies are done automagically by 'make dep', which also # removes any old dependencies. DON'T put your own dependencies here # unless it's something special (ie not a .c file). # # Note 2! The CFLAGS definitions are now in the main makefile... # .S.s: $(CPP) $(CFLAGS) $< -o $*.s .S.o: $(CC) $(CFLAGS) -c $< -o $*.o O_TARGET = ddb5476.o obj-y += setup.o irq.o int-handler.o pci.o pci_ops.o \ nile4_pic.o vrc5476_irq.o obj-$(CONFIG_REMOTE_DEBUG) += dbg_io.o include $(TOPDIR)/Rules.make --- NEW FILE: dbg_io.c --- /* * kgdb io functions for DDB5476. We use the second serial port. * * Copyright (C) 2001 MontaVista Software Inc. * Author: js...@mv... or js...@ju... * * 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 ======================== */ /* [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 /* * 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 /* ======================= END OF CONFIG ======================== */ typedef unsigned char uint8; typedef unsigned int uint32; #define UART16550_BAUD_2400 2400 #define UART16550_BAUD_4800 4800 #define UART16550_BAUD_9600 9600 #define UART16550_BAUD_19200 19200 #define UART16550_BAUD_38400 38400 #define UART16550_BAUD_57600 57600 #define UART16550_BAUD_115200 115200 #define UART16550_PARITY_NONE 0 #define UART16550_PARITY_ODD 0x08 #define UART16550_PARITY_EVEN 0x18 #define UART16550_PARITY_MARK 0x28 #define UART16550_PARITY_SPACE 0x38 #define UART16550_DATA_5BIT 0x0 #define UART16550_DATA_6BIT 0x1 #define UART16550_DATA_7BIT 0x2 #define UART16550_DATA_8BIT 0x3 #define UART16550_STOP_1BIT 0x0 #define UART16550_STOP_2BIT 0x4 /* register offset */ #define OFS_RCV_BUFFER 0 #define OFS_TRANS_HOLD 0 #define OFS_SEND_BUFFER 0 #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*REG_OFFSET) #define OFS_DIVISOR_MSB (1*REG_OFFSET) /* memory-mapped read/write of the port */ #define UART16550_READ(y) (*((volatile uint8*)(BASE + y))) #define UART16550_WRITE(y, z) ((*((volatile uint8*)(BASE + y))) = z) void debugInit(uint32 baud, uint8 data, uint8 parity, uint8 stop) { /* disable interrupts */ UART16550_WRITE(OFS_INTR_ENABLE, 0); /* set up buad rate */ { uint32 divisor; /* 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); /* clear DIAB bit */ UART16550_WRITE(OFS_LINE_CONTROL, 0x0); } /* set data format */ UART16550_WRITE(OFS_DATA_FORMAT, data | parity | stop); } uint8 getDebugChar(void) { 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(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; } --- NEW FILE: int-handler.S --- /* * Copyright 2001 MontaVista Software Inc. * Author: js...@mv... or js...@ju... * * 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 <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/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) --- NEW FILE: irq.c --- /* * arch/mips/ddb5476/irq.c -- NEC DDB Vrc-5476 interrupt routines * * Copyright (C) 2000 Geert Uytterhoeven <ge...@so...> * Sony Software Development Center Europe (SDCE), Brussels */ #include <linux/config.h> #include <linux/init.h> #include <linux/sched.h> #include <linux/types.h> #include <linux/interrupt.h> #include <linux/irq.h> #include <asm/io.h> #include <asm/ptrace.h> #include <asm/ddb5xxx/ddb5xxx.h> #define M1543_PNP_CONFIG 0x03f0 /* PnP Config Port */ #define M1543_PNP_INDEX 0x03f0 /* PnP Index Port */ #define M1543_PNP_DATA 0x03f1 /* PnP Data Port */ #define M1543_PNP_ALT_CONFIG 0x0370 /* Alternative PnP Config Port */ #define M1543_PNP_ALT_INDEX 0x0370 /* Alternative PnP Index Port */ #define M1543_PNP_ALT_DATA 0x0371 /* Alternative PnP Data Port */ #define M1543_INT1_MASTER_CTRL 0x0020 /* INT_1 (master) Control Register */ #define M1543_INT1_MASTER_MASK 0x0021 /* INT_1 (master) Mask Register */ #define M1543_INT1_SLAVE_CTRL 0x00a0 /* INT_1 (slave) Control Register */ #define M1543_INT1_SLAVE_MASK 0x00a1 /* INT_1 (slave) Mask Register */ #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 void m1543_irq_setup(void) { /* * The ALI M1543 has 13 interrupt inputs, IRQ1..IRQ13. Not all * the possible IO sources in the M1543 are in use by us. We will * use the following mapping: * * 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 * a conflict) * IRQ4 - reserved for UART A (default set by M1543) * IRQ5 - parallel (default set by M1543) * IRQ8 - DS1386 time of day (RTC) interrupt * IRQ9 - USB (hardwired in ddb_setup) * IRQ10 - PMU (hardwired in ddb_setup) * IRQ12 - mouse * IRQ14,15 - IDE controller (need to be confirmed, jsun) */ /* * Assing mouse interrupt to IRQ12 */ /* Enter configuration mode */ outb(0x51, M1543_PNP_CONFIG); outb(0x23, M1543_PNP_CONFIG); /* Select logical device 7 (Keyboard) */ outb(0x07, M1543_PNP_INDEX); outb(0x07, M1543_PNP_DATA); /* Select IRQ12 */ outb(0x72, M1543_PNP_INDEX); outb(0x0c, M1543_PNP_DATA); /* Leave configration mode */ outb(0xbb, M1543_PNP_CONFIG); } static void nile4_irq_setup(void) { int i; /* Map all interrupts to CPU int #0 (IP2) */ 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); /* PCI INTA#, B#, D# must be active low, INTC# must be active high */ nile4_set_pci_irq_polarity(0, 0); nile4_set_pci_irq_polarity(1, 0); nile4_set_pci_irq_polarity(2, 1); nile4_set_pci_irq_polarity(3, 0); for (i = 0; i < 16; i++) nile4_clear_irq(i); /* Enable CPU int #0 */ nile4_enable_irq_output(0); /* memory resource acquire in ddb_setup */ } static void error_action(int irq, void *dev_id, struct pt_regs *regs) { printk(KERN_ERR "Error interrupt happend: %d\n", irq); } static struct irqaction irq_cascade = { no_action, 0, 0, "cascade", NULL, NULL }; static struct irqaction irq_error = { no_action, 0, 0, "error", NULL, NULL }; 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 ddb5476_irq_setup(void) { /* hardware initialization */ nile4_irq_setup(); m1543_irq_setup(); /* 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); } --- NEW FILE: nile4_pic.c --- /* * arch/mips/ddb5476/nile4.c -- * low-level PIC code for NEC Vrc-5476 (Nile 4) * * Copyright (C) 2000 Geert Uytterhoeven <ge...@so...> * Sony Software Development Center Europe (SDCE), Brussels * * Copyright 2001 MontaVista Software Inc. * Author: js...@mv... or js...@ju... * */ #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 0x20, as it does for i386 */ return irq - 0x20; } #if defined(CONFIG_LL_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 --- NEW FILE: pci.c --- #include <linux/kernel.h> #include <linux/init.h> #include <linux/types.h> #include <linux/pci.h> #include <asm/pci_channel.h> #include <asm/ddb5xxx/ddb5xxx.h> #include <asm/ddb5xxx/debug.h> static struct resource extpci_io_resource = { "pci IO space", 0x1000, /* leave some room for ISA bus */ DDB_PCI_IO_SIZE -1, IORESOURCE_IO}; static struct resource extpci_mem_resource = { "pci memory space", DDB_PCI_MEM_BASE + 0x00100000, /* leave 1 MB for RTC */ DDB_PCI_MEM_BASE + DDB_PCI_MEM_SIZE -1, IORESOURCE_MEM}; extern struct pci_ops ddb5476_ext_pci_ops; struct pci_channel mips_pci_channels[] = { { &ddb5476_ext_pci_ops, &extpci_io_resource, &extpci_mem_resource }, { NULL, NULL, NULL} }; /* * we fix up irqs based on the slot number. * The first entry is at AD:11. * * This does not work for devices on sub-buses yet. */ /* * temporary */ #define PCI_EXT_INTA 8 #define PCI_EXT_INTB 9 #define PCI_EXT_INTC 10 #define PCI_EXT_INTD 11 #define PCI_EXT_INTE 12 /* * based on ddb5477 manual page 11 */ #define MAX_SLOT_NUM 21 static unsigned char irq_map[MAX_SLOT_NUM] = { /* SLOT: 0, AD:11 */ 0xff, /* SLOT: 1, AD:12 */ 0xff, /* SLOT: 2, AD:13 */ 9, /* SLOT: 3, AD:14 */ 10, /* SLOT: 4, AD:15 */ 0xff, /* SLOT: 5, AD:16 */ 0xff, /* SLOT: 6, AD:17 */ nile4_to_irq(PCI_EXT_INTB), /* SLOT: 7, AD:18 */ nile4_to_irq(PCI_EXT_INTC), /* SLOT: 8, AD:19 */ nile4_to_irq(PCI_EXT_INTD), /* SLOT: 9, AD:20 */ nile4_to_irq(PCI_EXT_INTA), /* SLOT: 10, AD:21 */ 0xff, /* SLOT: 11, AD:22 */ 0xff, /* SLOT: 12, AD:23 */ 0xff, /* SLOT: 13, AD:24 */ 14, /* HD controller, M5229 */ /* SLOT: 14, AD:25 */ 0xff, /* SLOT: 15, AD:26 */ 0xff, /* SLOT: 16, AD:27 */ 0xff, /* SLOT: 17, AD:28 */ 0xff, /* SLOT: 18, AD:29 */ 0xff, /* SLOT: 19, AD:30 */ 0xff, /* SLOT: 20, AD:31 */ 0xff }; extern int vrc5477_irq_to_irq(int irq); void __init pcibios_fixup_irqs(void) { struct pci_dev *dev; int slot_num; pci_for_each_dev(dev) { slot_num = PCI_SLOT(dev->devfn); MIPS_ASSERT(slot_num < MAX_SLOT_NUM); MIPS_ASSERT(irq_map[slot_num] != 0xff); pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq_map[slot_num]); dev->irq = irq_map[slot_num]; } } #if defined(CONFIG_LL_DEBUG) extern void jsun_scan_pci_bus(void); #endif void __init ddb_pci_reset_bus(void) { u32 temp; /* * I am not sure about the "official" procedure, the following * steps work as far as I know: * We first set PCI cold reset bit (bit 31) in PCICTRL-H. * Then we clear the PCI warm reset bit (bit 30) to 0 in PCICTRL-H. * The same is true for both PCI channels. */ temp = ddb_in32(DDB_PCICTRL+4); temp |= 0x80000000; ddb_out32(DDB_PCICTRL+4, temp); temp &= ~0xc0000000; ddb_out32(DDB_PCICTRL+4, temp); } unsigned __init int pcibios_assign_all_busses(void) { /* we hope pci_auto has assigned the bus numbers to all buses */ return 1; } void __init pcibios_fixup_resources(struct pci_dev *dev) { } void __init pcibios_fixup(void) { } --- NEW FILE: pci_ops.c --- /* * Copyright 2001 MontaVista Software Inc. * Author: Jun Sun, js...@mv... or js...@ju... * * arch/mips/ddb5xxx/ddb5477/pci_ops.c * Define the pci_ops for DB5477. * * Much of the code is derived from the original DDB5074 port by * Geert Uytterhoeven <ge...@so...> * * 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/config.h> #include <linux/pci.h> #include <linux/kernel.h> #include <linux/types.h> #include <asm/addrspace.h> #include <asm/ddb5xxx/debug.h> #include <asm/ddb5xxx/ddb5xxx.h> /* * config_swap structure records what set of pdar/pmr are used * to access pci config space. It also provides a place hold the * original values for future restoring. */ struct pci_config_swap { u32 pdar; u32 pmr; u32 config_base; u32 config_size; u32 pdar_backup; u32 pmr_backup; }; /* * On DDB5476, we have one set of swap registers */ struct pci_config_swap ext_pci_swap = { DDB_PCIW0, DDB_PCIINIT0, DDB_PCI_CONFIG_BASE, DDB_PCI_CONFIG_SIZE }; static int pci_config_workaround=1; /* * access config space */ static inline u32 ddb_access_config_base(struct pci_config_swap *swap, u32 bus,/* 0 means top level bus */ u32 slot_num) { u32 pci_addr = 0; u32 pciinit_offset = 0; u32 virt_addr = swap->config_base; u32 option; if (pci_config_workaround) { /* [jsun] work around Vrc5476 controller itself */ if (slot_num == 12) slot_num = 0; /* BUG : skip P2P bridge for now */ if (slot_num == 5) slot_num = 0; } else { if (slot_num == 12) return DDB_BASE + DDB_PCI_BASE; } /* minimum pdar (window) size is 2MB */ MIPS_ASSERT(swap->config_size >= (2 << 20)); MIPS_ASSERT(slot_num < (1 << 5)); MIPS_ASSERT(bus < (1 << 8)); /* backup registers */ swap->pdar_backup = ddb_in32(swap->pdar); swap->pmr_backup = ddb_in32(swap->pmr); /* set the pdar (pci window) register */ ddb_set_pdar(swap->pdar, swap->config_base, swap->config_size, 32, /* 32 bit wide */ 0, /* not on local memory bus */ 0); /* not visible from PCI bus (N/A) */ /* * calcuate the absolute pci config addr; * according to the spec, we start scanning from adr:11 (0x800) */ if (bus == 0) { /* type 0 config */ pci_addr = 0x800 << slot_num; } else { /* type 1 config */ pci_addr = (bus << 16) | (slot_num << 11); panic("ddb_access_config_base: we don't support type 1 config Yet"); } /* * if pci_addr is less than pci config window size, we set * pciinit_offset to 0 and adjust the virt_address. * Otherwise we will try to adjust pciinit_offset. */ if (pci_addr < swap->config_size) { virt_addr = KSEG1ADDR(swap->config_base + pci_addr); pciinit_offset = 0; } else { MIPS_ASSERT( (pci_addr & (swap->config_size - 1)) == 0); virt_addr = KSEG1ADDR(swap->config_base); pciinit_offset = pci_addr; } /* set the pmr register */ option = DDB_PCI_ACCESS_32; if (bus != 0) option |= DDB_PCI_CFGTYPE1; ddb_set_pmr(swap->pmr, DDB_PCICMD_CFG, pciinit_offset, option); return virt_addr; } static inline void ddb_close_config_base(struct pci_config_swap *swap) { ddb_out32(swap->pdar, swap->pdar_backup); ddb_out32(swap->pmr, swap->pmr_backup); } static int read_config_dword(struct pci_config_swap *swap, struct pci_dev *dev, u32 where, u32 *val) { u32 bus, slot_num, func_num; u32 base; MIPS_ASSERT((where & 3) == 0); MIPS_ASSERT(where < (1 << 8)); /* check if the bus is top-level */ if (dev->bus->parent != NULL) { bus = dev->bus->number; MIPS_ASSERT(bus != 0); } else { bus = 0; } slot_num = PCI_SLOT(dev->devfn); func_num = PCI_FUNC(dev->devfn); base = ddb_access_config_base(swap, bus, slot_num); *val = *(volatile u32*) (base + (func_num << 8) + where); ddb_close_config_base(swap); return PCIBIOS_SUCCESSFUL; } static int read_config_word(struct pci_config_swap *swap, struct pci_dev *dev, u32 where, u16 *val) { int status; u32 result; MIPS_ASSERT((where & 1) == 0); status = read_config_dword(swap, dev, where & ~3, &result); if (where & 2) result >>= 16; *val = result & 0xffff; return status; } static int read_config_byte(struct pci_config_swap *swap, struct pci_dev *dev, u32 where, u8 *val) { int status; u32 result; status = read_config_dword(swap, dev, where & ~3, &result); if (where & 1) result >>= 8; if (where & 2) result >>= 16; *val = result & 0xff; return status; } static int write_config_dword(struct pci_config_swap *swap, struct pci_dev *dev, u32 where, u32 val) { u32 bus, slot_num, func_num; u32 base; MIPS_ASSERT((where & 3) == 0); MIPS_ASSERT(where < (1 << 8)); /* check if the bus is top-level */ if (dev->bus->parent != NULL) { bus = dev->bus->number; MIPS_ASSERT(bus != 0); } else { bus = 0; } slot_num = PCI_SLOT(dev->devfn); func_num = PCI_FUNC(dev->devfn); base = ddb_access_config_base(swap, bus, slot_num); *(volatile u32*) (base + (func_num << 8) + where) = val; ddb_close_config_base(swap); return PCIBIOS_SUCCESSFUL; } static int write_config_word(struct pci_config_swap *swap, struct pci_dev *dev, u32 where, u16 val) { int status, shift=0; u32 result; MIPS_ASSERT((where & 1) == 0); status = read_config_dword(swap, dev, where & ~3, &result); if (status != PCIBIOS_SUCCESSFUL) return status; if (where & 2) shift += 16; result &= ~(0xffff << shift); result |= val << shift; return write_config_dword(swap, dev, where & ~3, result); } static int write_config_byte(struct pci_config_swap *swap, struct pci_dev *dev, u32 where, u8 val) { int status, shift=0; u32 result; status = read_config_dword(swap, dev, where & ~3, &result); if (status != PCIBIOS_SUCCESSFUL) return status; if (where & 2) shift += 16; if (where & 1) shift += 8; result &= ~(0xff << shift); result |= val << shift; return write_config_dword(swap, dev, where & ~3, result); } #define MAKE_PCI_OPS(prefix, rw, unitname, unittype, pciswap) \ static int prefix##_##rw##_config_##unitname(struct pci_dev *dev, int where, unittype val) \ { \ return rw##_config_##unitname(pciswap, \ dev, \ where, \ val); \ } MAKE_PCI_OPS(extpci, read, byte, u8 *, &ext_pci_swap) MAKE_PCI_OPS(extpci, read, word, u16 *, &ext_pci_swap) MAKE_PCI_OPS(extpci, read, dword, u32 *, &ext_pci_swap) MAKE_PCI_OPS(extpci, write, byte, u8, &ext_pci_swap) MAKE_PCI_OPS(extpci, write, word, u16, &ext_pci_swap) MAKE_PCI_OPS(extpci, write, dword, u32, &ext_pci_swap) struct pci_ops ddb5476_ext_pci_ops ={ extpci_read_config_byte, extpci_read_config_word, extpci_read_config_dword, extpci_write_config_byte, extpci_write_config_word, extpci_write_config_dword }; #if defined(CONFIG_LL_DEBUG) void jsun_scan_pci_bus(void) { struct pci_bus bus; struct pci_dev dev; unsigned int devfn; int j; pci_config_workaround = 0; bus.parent = NULL; /* we scan the top level only */ dev.bus = &bus; dev.sysdata = NULL; /* scan ext pci bus and io pci bus*/ for (j=0; j< 1; j++) { printk(KERN_INFO "scan ddb5476 external PCI bus:\n"); bus.ops = &ddb5476_ext_pci_ops; for (devfn = 0; devfn < 0x100; devfn += 8) { u32 temp; u16 temp16; u8 temp8; int i; dev.devfn = devfn; MIPS_VERIFY(pci_read_config_dword(&dev, 0, &temp), == PCIBIOS_SUCCESSFUL); if (temp == 0xffffffff) continue; printk(KERN_INFO "slot %d: (addr %d) \n", devfn/8, 11+devfn/8); /* verify read word and byte */ MIPS_VERIFY(pci_read_config_word(&dev, 2, &temp16), == PCIBIOS_SUCCESSFUL); MIPS_ASSERT(temp16 == (temp >> 16)); MIPS_VERIFY(pci_read_config_byte(&dev, 3, &temp8), == PCIBIOS_SUCCESSFUL); MIPS_ASSERT(temp8 == (temp >> 24)); MIPS_VERIFY(pci_read_config_byte(&dev, 1, &temp8), == PCIBIOS_SUCCESSFUL); MIPS_ASSERT(temp8 == ((temp >> 8) & 0xff)); for (i=0; i < 16; i++) { if ((i%4) == 0) printk(KERN_INFO); MIPS_VERIFY(pci_read_config_dword(&dev, i*4, &temp), == PCIBIOS_SUCCESSFUL); printk("\t%08X", temp); if ((i%4) == 3) printk("\n"); } } } pci_config_workaround = 1; } #endif --- NEW FILE: setup.c --- /* * arch/mips/ddb5476/setup.c -- NEC DDB Vrc-5476 setup routines * * Copyright (C) 2000 Geert Uytterhoeven <ge...@so...> * Sony Software Development Center Europe (SDCE), Brussels */ #include <linux/config.h> #include <linux/init.h> #include <linux/kbd_ll.h> #include <linux/kernel.h> #include <linux/kdev_t.h> #include <linux/types.h> #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 <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/ddb5xxx/ddb5xxx.h> #ifdef CONFIG_REMOTE_DEBUG extern void rs_kgdb_hook(int); extern void breakpoint(void); #endif #if defined(CONFIG_SERIAL_CONSOLE) extern void console_setup(char *); #endif extern struct ide_ops std_ide_ops; extern struct kbd_ops std_kbd_ops; static void (*back_to_prom) (void) = (void (*)(void)) 0xbfc00000; static void ddb_machine_restart(char *command) { u32 t; /* PCI cold reset */ t = ddb_in32(DDB_PCICTRL + 4); t |= 0x40000000; ddb_out32(DDB_PCICTRL + 4, t); /* CPU cold reset */ t = ddb_in32(DDB_CPUSTAT); t |= 1; ddb_out32(DDB_CPUSTAT, t); /* Call the PROM */ back_to_prom(); } static void ddb_machine_halt(void) { printk(KERN_NOTICE "DDB Vrc-5476 halted.\n"); while (1); } static void ddb_machine_power_off(void) { printk(KERN_NOTICE "DDB Vrc-5476 halted. Please turn off the power.\n"); while (1); } extern void ddb_irq_setup(void); extern void rtc_ds1386_init(unsigned long base); static void __init ddb_time_init(void) { mips_counter_frequency = 83000000; /* we have ds1396 RTC chip */ rtc_ds1386_init(KSEG1ADDR(DDB_PCI_MEM_BASE)); /* optional: we don't have a good way to set RTC time, * so we will hack here to set a time. In normal running. * it should *not* be called becaues RTC will keep the correct time. */ /* rtc_set_time(mktime(2001, 10, 05, 17, 20, 0)); */ } extern int setup_irq(unsigned int irq, struct irqaction *irqaction); static void __init ddb_timer_setup(struct irqaction *irq) { unsigned int count; /* we are using the cpu counter for timer interrupts */ setup_irq(CPU_IRQ_BASE + 7, irq); /* to generate the first timer interrupt */ count = read_32bit_cp0_register(CP0_COUNT); write_32bit_cp0_register(CP0_COMPARE, count + 1000); } static struct { struct resource dma1; struct resource pic1; struct resource timer; struct resource rtc; struct resource dma_page_reg; struct resource pic2; struct resource dma2; } ddb5476_ioport = { { "dma1", 0x00, 0x1f, IORESOURCE_BUSY}, { "pic1", 0x20, 0x3f, IORESOURCE_BUSY}, { "timer", 0x40, 0x5f, IORESOURCE_BUSY}, { "rtc", 0x70, 0x7f, IORESOURCE_BUSY}, { "dma page reg", 0x80, 0x8f, IORESOURCE_BUSY}, { "pic2", 0xa0, 0xbf, IORESOURCE_BUSY}, { "dma2", 0xc0, 0xdf, IORESOURCE_BUSY} }; static struct { struct resource nile4; } ddb5476_iomem = { { "Nile 4", DDB_BASE, DDB_BASE + DDB_SIZE - 1, IORESOURCE_BUSY} }; static void ddb5476_board_init(void); extern void ddb5476_irq_setup(void); extern void (*irq_setup)(void); void __init ddb_setup(void) { extern int panic_timeout; irq_setup = ddb5476_irq_setup; mips_io_port_base = KSEG1ADDR(DDB_PCI_IO_BASE); board_time_init = ddb_time_init; board_timer_setup = ddb_timer_setup; _machine_restart = ddb_machine_restart; _machine_halt = ddb_machine_halt; _machine_power_off = ddb_machine_power_off; /* request io port/mem resources */ if (request_resource(&ioport_resource, &ddb5476_ioport.dma1) || request_resource(&ioport_resource, &ddb5476_ioport.pic1) || request_resource(&ioport_resource, &ddb5476_ioport.timer) || request_resource(&ioport_resource, &ddb5476_ioport.rtc) || request_resource(&ioport_resource, &ddb5476_ioport.dma_page_reg) || request_resource(&ioport_resource, &ddb5476_ioport.pic2) || request_resource(&ioport_resource, &ddb5476_ioport.dma2) || request_resource(&iomem_resource, &ddb5476_iomem.nile4)) { printk ("ddb_setup - requesting oo port resources failed.\n"); for (;;); } #ifdef CONFIG_BLK_DEV_IDE ide_ops = &std_ide_ops; #endif #ifdef CONFIG_PC_KEYB kbd_ops = &std_kbd_ops; #endif /* Reboot on panic */ panic_timeout = 180; /* [jsun] we need to set BAR0 so that SDRAM 0 appears at 0x0 in PCI */ /* *(long*)0xbfa00218 = 0x8; */ #ifdef CONFIG_FB conswitchp = &dummy_con; #endif /* board initialization stuff */ ddb5476_board_init(); } /* * We don't trust bios. We essentially does hardware re-initialization * as complete as possible, as far as we know we can safely do. */ static void ddb5476_board_init(void) { /* ----------- setup PDARs ------------ */ /* check SDRAM0, whether we are on MEM bus does not matter */ MIPS_ASSERT((ddb_in32(DDB_SDRAM0) & 0xffffffef) == ddb_calc_pdar(DDB_SDRAM_BASE, DDB_SDRAM_SIZE, 32, 0, 1)); /* SDRAM1 should be turned off. What is this for anyway ? */ MIPS_ASSERT( (ddb_in32(DDB_SDRAM1) & 0xf) == 0); /* flash 1&2, DDB status, DDB control */ ddb_set_pdar(DDB_DCS2, DDB_DCS2_BASE, DDB_DCS2_SIZE, 16, 0, 0); ddb_set_pdar(DDB_DCS3, DDB_DCS3_BASE, DDB_DCS3_SIZE, 16, 0, 0); ddb_set_pdar(DDB_DCS4, DDB_DCS4_BASE, DDB_DCS4_SIZE, 8, 0, 0); ddb_set_pdar(DDB_DCS5, DDB_DCS5_BASE, DDB_DCS5_SIZE, 8, 0, 0); /* shut off other pdar so they don't accidentally get into the way */ ddb_set_pdar(DDB_DCS6, 0xffffffff, 0, 32, 0, 0); ddb_set_pdar(DDB_DCS7, 0xffffffff, 0, 32, 0, 0); ddb_set_pdar(DDB_DCS8, 0xffffffff, 0, 32, 0, 0); /* verify VRC5477 base addr */ /* don't care about some details */ MIPS_ASSERT((ddb_in32(DDB_INTCS) & 0xffffff0f) == ddb_calc_pdar(DDB_INTCS_BASE, DDB_INTCS_SIZE, 8, 0, 0)); /* verify BOOT ROM addr */ /* don't care about some details */ MIPS_ASSERT((ddb_in32(DDB_BOOTCS) & 0xffffff0f) == ddb_calc_pdar(DDB_BOOTCS_BASE, DDB_BOOTCS_SIZE, 8, 0, 0)); /* setup PCI windows - window1 for MEM/config, window0 for IO */ ddb_set_pdar(DDB_PCIW0, DDB_PCI_IO_BASE, DDB_PCI_IO_SIZE, 32, 0, 1); ddb_set_pmr(DDB_PCIINIT0, DDB_PCICMD_IO, 0, DDB_PCI_ACCESS_32); ddb_set_pdar(DDB_PCIW1, DDB_PCI_MEM_BASE, DDB_PCI_MEM_SIZE, 32, 0, 1); ddb_set_pmr(DDB_PCIINIT1, DDB_PCICMD_MEM, DDB_PCI_MEM_BASE, DDB_PCI_ACCESS_32); /* ----------- setup PDARs ------------ */ /* this is problematic - it will reset Aladin which cause we loose * serial port, and we don't know how to set up Aladin chip again. */ // ddb_pci_reset_bus(); ddb_out32(DDB_BAR0, 0x00000008); ddb_out32(DDB_BARC, 0xffffffff); ddb_out32(DDB_BARB, 0xffffffff); ddb_out32(DDB_BAR1, 0xffffffff); ddb_out32(DDB_BAR2, 0xffffffff); ddb_out32(DDB_BAR3, 0xffffffff); ddb_out32(DDB_BAR4, 0xffffffff); ddb_out32(DDB_BAR5, 0xffffffff); ddb_out32(DDB_BAR6, 0xffffffff); ddb_out32(DDB_BAR7, 0xffffffff); ddb_out32(DDB_BAR8, 0xffffffff); /* ----------- switch PCI1 to PCI CONFIG space ------------ */ ddb_set_pdar(DDB_PCIW1, DDB_PCI_CONFIG_BASE, DDB_PCI_CONFIG_SIZE, 32, 0, 1); ddb_set_pmr(DDB_PCIINIT1, DDB_PCICMD_CFG, 0x0, DDB_PCI_ACCESS_32); /* ----- M1543 PCI setup ------ */ /* we know M1543 PCI-ISA controller is at addr:18 */ /* xxxx1010 makes USB at addr:13 and PMU at addr:14 */ *(volatile unsigned char *) 0xa8040072 &= 0xf0; *(volatile unsigned char *) 0xa8040072 |= 0xa; /* setup USB interrupt to IRQ 9, (bit 0:3 - 0001) * no IOCHRDY signal, (bit 7 - 1) * M1543C & M7101 VID and Subsys Device ID are read-only (bit 6 - 1) * Bypass USB Master INTAJ level to edge conversion (bit 4 - 0) */ *(unsigned char *) 0xa8040074 = 0xc1; /* setup PMU(SCI to IRQ 10 (bit 0:3 - 0011) * SCI routing to IRQ 13 disabled (bit 7 - 1) * SCI interrupt level to edge conversion bypassed (bit 4 - 0) */ *(unsigned char *) 0xa8040076 = 0x83; /* setup IDE controller * enable IDE controller (bit 6 - 1) * IDE IDSEL to be addr:24 (bit 4:5 - 11) * no IDE ATA Secondary Bus Signal Pad Control (bit 3 - 0) * no IDE ATA Primary Bus Signal Pad Control (bit 2 - 0) * primary IRQ is 14, secondary is 15 (bit 1:0 - 01 */ // *(unsigned char*)0xa8040058 = 0x71; // *(unsigned char*)0xa8040058 = 0x79; // *(unsigned char*)0xa8040058 = 0x74; // use SIRQ, primary tri-state *(unsigned char *) 0xa8040058 = 0x75; // primary tri-state #if 0 /* this is not necessary if M5229 does not use SIRQ */ *(unsigned char *) 0xa8040044 = 0x0d; // primary to IRQ 14 *(unsigned char *) 0xa8040075 = 0x0d; // secondary to IRQ 14 #endif /* enable IDE in the M5229 config register 0x50 (bit 0 - 1) */ /* M5229 IDSEL is addr:24; see above setting */ *(unsigned char *) 0xa9000050 |= 0x1; /* enable bus master (bit 2) and IO decoding (bit 0) */ *(unsigned char *) 0xa9000004 |= 0x5; /* enable native, copied from arch/ppc/k2boot/head.S */ /* TODO - need volatile, need to be portable */ *(unsigned char *) 0xa9000009 = 0xff; /* ----- end of M1543 PCI setup ------ */ /* ----- reset on-board ether chip ------ */ *((volatile u32 *) 0xa8020004) |= 1; /* decode I/O */ *((volatile u32 *) 0xa8020010) = 0; /* set BAR address */ /* send reset command */ *((volatile u32 *) 0xa6000000) = 1; /* do a soft reset */ /* disable ether chip */ *((volatile u32 *) 0xa8020004) = 0; /* disable any decoding */ /* put it into sleep */ *((volatile u32 *) 0xa8020040) = 0x80000000; /* ----- end of reset on-board ether chip ------ */ /* ----------- switch PCI1 back to PCI MEM space ------------ */ ddb_set_pdar(DDB_PCIW1, DDB_PCI_MEM_BASE, DDB_PCI_MEM_SIZE, 32, 0, 1); ddb_set_pmr(DDB_PCIINIT1, DDB_PCICMD_MEM, DDB_PCI_MEM_BASE, DDB_PCI_ACCESS_32); } --- NEW FILE: vrc5476_irq.c --- /* * The irq controller for vrc5476. * * Copyright (C) 2001 MontaVista Software Inc. * Author: js...@mv... or js...@ju... * * 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/types.h> #include <linux/ptrace.h> #include <asm/system.h> #include <asm/ddb5xxx/ddb5xxx.h> #include <asm/ddb5xxx/debug.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); } #define vrc5476_irq_end vrc5476_irq_enable 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 unsigned int do_IRQ(int irq, 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(); } |