summaryrefslogtreecommitdiffstats
path: root/arch/mips/gt64120/common
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2001-02-05 01:33:01 +0000
committerRalf Baechle <ralf@linux-mips.org>2001-02-05 01:33:01 +0000
commit222ce6477d35d0b51fe9d5fb16ada90ac3341500 (patch)
tree33dc535dde84fab2a5cd175e0bfda393d5970f42 /arch/mips/gt64120/common
parent41f766e193858f7b5d1f9e81f50f392c1bd40f32 (diff)
Start of an attempt to unify support for GT64120 based boards.
Diffstat (limited to 'arch/mips/gt64120/common')
-rw-r--r--arch/mips/gt64120/common/.cvsignore2
-rw-r--r--arch/mips/gt64120/common/Makefile18
-rw-r--r--arch/mips/gt64120/common/gt_irq.c253
-rw-r--r--arch/mips/gt64120/common/irq.c299
-rw-r--r--arch/mips/gt64120/common/pci.c1140
5 files changed, 1712 insertions, 0 deletions
diff --git a/arch/mips/gt64120/common/.cvsignore b/arch/mips/gt64120/common/.cvsignore
new file mode 100644
index 000000000..857dd22e9
--- /dev/null
+++ b/arch/mips/gt64120/common/.cvsignore
@@ -0,0 +1,2 @@
+.depend
+.*.flags
diff --git a/arch/mips/gt64120/common/Makefile b/arch/mips/gt64120/common/Makefile
new file mode 100644
index 000000000..ccf50a55b
--- /dev/null
+++ b/arch/mips/gt64120/common/Makefile
@@ -0,0 +1,18 @@
+#
+# Makefile for common code of gt64120-based boards.
+#
+# 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).
+#
+
+.S.s:
+ $(CPP) $(CFLAGS) $< -o $*.s
+.S.o:
+ $(CC) $(CFLAGS) -c $< -o $*.o
+
+O_TARGET:= gt64120.o
+
+obj-y := gt_irq.o irq.o pci.o
+
+include $(TOPDIR)/Rules.make
diff --git a/arch/mips/gt64120/common/gt_irq.c b/arch/mips/gt64120/common/gt_irq.c
new file mode 100644
index 000000000..afd91e4ba
--- /dev/null
+++ b/arch/mips/gt64120/common/gt_irq.c
@@ -0,0 +1,253 @@
+/***********************************************************************
+ *
+ * Copyright 2001 MontaVista Software Inc.
+ * Author: jsun@mvista.com or jsun@junsun.net
+ *
+ * arch/mips/gt64120/common/gt_irq.c
+ * Interrupt routines for gt64120. Currently it only handles timer irq.
+ *
+ * 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/module.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <asm/ptrace.h>
+#include <linux/config.h>
+#include <linux/sched.h>
+#include <linux/kernel_stat.h>
+#include <asm/io.h>
+#include <asm/gt64120/gt64120.h>
+
+/*
+ * These are interrupt handlers for the GT on-chip interrupts. They
+ * all come in to the MIPS on a single interrupt line, and have to
+ * be handled and ack'ed differently than other MIPS interrupts.
+ */
+
+#if CURRENTLY_UNUSED
+
+struct tq_struct irq_handlers[MAX_CAUSE_REGS][MAX_CAUSE_REG_WIDTH];
+void hook_irq_handler(int int_cause, int bit_num, void *isr_ptr);
+
+/*
+ * Hooks IRQ handler to the system. When the system is interrupted
+ * the interrupt service routine is called.
+ *
+ * Inputs :
+ * int_cause - The interrupt cause number. In EVB64120 two parameters
+ * are declared, INT_CAUSE_MAIN and INT_CAUSE_HIGH.
+ * bit_num - Indicates which bit number in the cause register
+ * isr_ptr - Pointer to the interrupt service routine
+ */
+void hook_irq_handler(int int_cause, int bit_num, void *isr_ptr)
+{
+ irq_handlers[int_cause][bit_num].routine = isr_ptr;
+}
+
+
+/*
+ * Enables the IRQ on Galileo Chip
+ *
+ * Inputs :
+ * int_cause - The interrupt cause number. In EVB64120 two parameters
+ * are declared, INT_CAUSE_MAIN and INT_CAUSE_HIGH.
+ * bit_num - Indicates which bit number in the cause register
+ *
+ * Outputs :
+ * 1 if succesful, 0 if failure
+ */
+int enable_galileo_irq(int int_cause, int bit_num)
+{
+ if (int_cause == INT_CAUSE_MAIN)
+ SET_REG_BITS(CPU_INTERRUPT_MASK_REGISTER, (1 << bit_num));
+ else if (int_cause == INT_CAUSE_HIGH)
+ SET_REG_BITS(CPU_HIGH_INTERRUPT_MASK_REGISTER,
+ (1 << bit_num));
+ else
+ return 0;
+
+ return 1;
+}
+
+/*
+ * Disables the IRQ on Galileo Chip
+ *
+ * Inputs :
+ * int_cause - The interrupt cause number. In EVB64120 two parameters
+ * are declared, INT_CAUSE_MAIN and INT_CAUSE_HIGH.
+ * bit_num - Indicates which bit number in the cause register
+ *
+ * Outputs :
+ * 1 if succesful, 0 if failure
+ */
+int disable_galileo_irq(int int_cause, int bit_num)
+{
+ if (int_cause == INT_CAUSE_MAIN)
+ RESET_REG_BITS(CPU_INTERRUPT_MASK_REGISTER,
+ (1 << bit_num));
+ else if (int_cause == INT_CAUSE_HIGH)
+ RESET_REG_BITS(CPU_HIGH_INTERRUPT_MASK_REGISTER,
+ (1 << bit_num));
+ else
+ return 0;
+ return 1;
+}
+#endif /* UNUSED */
+
+/*
+ * Interrupt handler for interrupts coming from the Galileo chip.
+ * It could be timer interrupt, built in ethernet ports etc...
+ */
+static void gt64120_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+ unsigned int irq_src, int_high_src, irq_src_mask,
+ int_high_src_mask;
+ int handled;
+
+ GT_READ(GT_INTRCAUSE_OFS, &irq_src);
+ GT_READ(GT_INTRMASK_OFS, &irq_src_mask);
+ GT_READ(GT_HINTRCAUSE_OFS, &int_high_src);
+ GT_READ(GT_HINTRMASK_OFS, &int_high_src_mask);
+ irq_src = irq_src & irq_src_mask;
+ int_high_src = int_high_src & int_high_src_mask;
+
+ handled = 0;
+
+ /* Execute all interrupt handlers */
+ /* Check for timer interrupt */
+ if (irq_src & 0x00000800) {
+ handled = 1;
+ irq_src &= ~0x00000800;
+ // RESET_REG_BITS (INTERRUPT_CAUSE_REGISTER,BIT8);
+ do_timer(regs);
+ }
+
+ if (irq_src) {
+ printk(KERN_INFO
+ "Other Galileo interrupt received irq_src %x\n",
+ irq_src);
+#if CURRENTLY_UNUSED
+ for (count = 0; count < MAX_CAUSE_REG_WIDTH; count++) {
+ if (irq_src & (1 << count)) {
+ if (irq_handlers[INT_CAUSE_MAIN][count].
+ routine) {
+ queue_task(&irq_handlers
+ [INT_CAUSE_MAIN][count],
+ &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
+ handled = 1;
+ }
+ }
+ }
+#endif /* UNUSED */
+ }
+ GT_WRITE(GT_INTRCAUSE_OFS, 0);
+ GT_WRITE(GT_HINTRCAUSE_OFS, 0);
+
+#undef GALILEO_I2O
+#ifdef GALILEO_I2O
+ /*
+ * Future I2O support. We currently attach I2O interrupt handlers to
+ * the Galileo interrupt (int 4) and handle them in do_IRQ.
+ */
+ if (isInBoundDoorBellInterruptSet()) {
+ printk(KERN_INFO "I2O doorbell interrupt received.\n");
+ handled = 1;
+ }
+
+ if (isInBoundPostQueueInterruptSet()) {
+ printk(KERN_INFO "I2O Queue interrupt received.\n");
+ handled = 1;
+ }
+
+ /*
+ * This normally would be outside of the ifdef, but since we're
+ * handling I2O outside of this handler, this printk shows up every
+ * time we get a valid I2O interrupt. So turn this off for now.
+ */
+ if (handled == 0) {
+ if (counter < 50) {
+ printk("Spurious Galileo interrupt...\n");
+ counter++;
+ }
+ }
+#endif
+}
+
+/*
+ * Initializes timer using galileo's built in timer.
+ */
+#ifdef CONFIG_SYSCLK_100
+#define Sys_clock (100 * 1000000) // 100 MHz
+#endif
+#ifdef CONFIG_SYSCLK_83
+#define Sys_clock (83.333 * 1000000) // 83.333 MHz
+#endif
+#ifdef CONFIG_SYSCLK_75
+#define Sys_clock (75 * 1000000) // 75 MHz
+#endif
+
+/*
+ * This will ignore the standard MIPS timer interrupt handler
+ * that is passed in as *irq (=irq0 in ../kernel/time.c).
+ * We will do our own timer interrupt handling.
+ */
+void gt64120_time_init(struct irqaction *irq)
+{
+ extern irq_desc_t irq_desc[NR_IRQS];
+ static struct irqaction timer;
+
+ /* Disable timer first */
+ GT_WRITE(GT_TC_CONTROL_OFS, 0);
+ /* Load timer value for 100 Hz */
+ GT_WRITE(GT_TC3_OFS, Sys_clock / 100);
+
+ /*
+ * Create the IRQ structure entry for the timer. Since we're too early
+ * in the boot process to use the "request_irq()" call, we'll hard-code
+ * the values to the correct interrupt line.
+ */
+ timer.handler = &gt64120_irq;
+ timer.flags = SA_SHIRQ | SA_INTERRUPT;
+ timer.name = "timer";
+ timer.dev_id = NULL;
+ timer.next = NULL;
+ timer.mask = 0;
+ irq_desc[TIMER].action = &timer;
+
+ enable_irq(TIMER);
+
+ /* Enable timer ints */
+ GT_WRITE(GT_TC_CONTROL_OFS, 0xc0);
+ /* clear Cause register first */
+ GT_WRITE(GT_INTRCAUSE_OFS, 0x0);
+ /* Unmask timer int */
+ GT_WRITE(GT_INTRMASK_OFS, 0x800);
+ /* Clear High int register */
+ GT_WRITE(GT_HINTRCAUSE_OFS, 0x0);
+ /* Mask All interrupts at High cause interrupt */
+ GT_WRITE(GT_HINTRMASK_OFS, 0x0);
+}
+
+void gt64120_irq_init(void)
+{
+#if CURRENTLY_UNUSED
+ int i, j;
+
+ /* Reset irq handlers pointers to NULL */
+ for (i = 0; i < MAX_CAUSE_REGS; i++) {
+ for (j = 0; j < MAX_CAUSE_REG_WIDTH; j++) {
+ irq_handlers[i][j].next = NULL;
+ irq_handlers[i][j].sync = 0;
+ irq_handlers[i][j].routine = NULL;
+ irq_handlers[i][j].data = NULL;
+ }
+ }
+#endif
+}
diff --git a/arch/mips/gt64120/common/irq.c b/arch/mips/gt64120/common/irq.c
new file mode 100644
index 000000000..c0fdcc44a
--- /dev/null
+++ b/arch/mips/gt64120/common/irq.c
@@ -0,0 +1,299 @@
+/*
+ * arch/mips/gt64120/common/irq.c
+ * Top-level irq code. This is really common among all MIPS boards.
+ * Should be "upgraded" to arch/mips/kernel/irq.c
+ *
+ * Copyright (C) 2000 RidgeRun, Inc.
+ * Author: RidgeRun, Inc.
+ * glonnon@ridgerun.com, skranz@ridgerun.com, stevej@ridgerun.com
+ *
+ * Copyright 2001 MontaVista Software Inc.
+ * Author: Jun Sun, 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.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/kernel_stat.h>
+#include <linux/module.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/timex.h>
+#include <linux/malloc.h>
+#include <linux/random.h>
+#include <linux/irq.h>
+#include <asm/bitops.h>
+#include <asm/bootinfo.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/mipsregs.h>
+#include <asm/system.h>
+#include <asm/pmc/ev64120int.h>
+
+
+#undef IRQ_DEBUG
+
+#ifdef IRQ_DEBUG
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...)
+#endif
+
+
+/*
+ * Generic no controller code
+ */
+
+static void no_irq_enable_disable(unsigned int irq)
+{
+}
+
+static unsigned int no_irq_startup(unsigned int irq)
+{
+ return 0;
+}
+
+static void no_irq_ack(unsigned int irq)
+{
+ printk(KERN_CRIT "Unexpected IRQ trap at vector %u\n", irq);
+}
+
+struct hw_interrupt_type no_irq_type = {
+ typename: "none",
+ startup: no_irq_startup,
+ shutdown: no_irq_enable_disable,
+ enable: no_irq_enable_disable,
+ disable: no_irq_enable_disable,
+ // ack: no_irq_ack,
+ // [jsun] cannot use it yet. gt64120 does not have its own handler
+ ack: NULL,
+ end: no_irq_enable_disable,
+};
+
+
+
+/*
+ * Controller mappings for all interrupt sources:
+ */
+irq_desc_t irq_desc[NR_IRQS];
+
+unsigned long spurious_count = 0;
+
+int get_irq_list(char *buf)
+{
+ int i, len = 0, j;
+ struct irqaction *action;
+
+ len += sprintf(buf + len, " ");
+ for (j = 0; j < smp_num_cpus; j++)
+ len += sprintf(buf + len, "CPU%d ", j);
+ *(char *) (buf + len++) = '\n';
+
+ for (i = 0; i < NR_IRQS; i++) {
+ action = irq_desc[i].action;
+ if (!action || !action->handler)
+ continue;
+ len += sprintf(buf + len, "%3d: ", i);
+ len += sprintf(buf + len, "%10u ", kstat_irqs(i));
+ if (irq_desc[i].handler)
+ len +=
+ sprintf(buf + len, " %s ",
+ irq_desc[i].handler->typename);
+ else
+ len += sprintf(buf + len, " None ");
+ len += sprintf(buf + len, " %s", action->name);
+ for (action = action->next; action; action = action->next) {
+ len += sprintf(buf + len, ", %s", action->name);
+ }
+ len += sprintf(buf + len, "\n");
+ }
+ len += sprintf(buf + len, "BAD: %10lu\n", spurious_count);
+ return len;
+}
+
+asmlinkage void do_IRQ(int irq, struct pt_regs *regs)
+{
+ struct irqaction *action;
+ int cpu;
+ cpu = smp_processor_id();
+ irq_enter(cpu, irq);
+ kstat.irqs[cpu][irq]++;
+ if (irq_desc[irq].handler->ack) {
+ irq_desc[irq].handler->ack(irq);
+ }
+
+ disable_irq(irq);
+
+ action = irq_desc[irq].action;
+ if (action && action->handler) {
+#ifdef IRQ_DEBUG
+ if (irq != TIMER)
+ DBG(KERN_INFO
+ "rr: irq %d action %p and handler %p\n", irq,
+ action, action->handler);
+#endif
+ if (!(action->flags & SA_INTERRUPT))
+ __sti();
+ do {
+ action->handler(irq, action->dev_id, regs);
+ action = action->next;
+ } while (action);
+ __cli();
+ if (irq_desc[irq].handler) {
+ if (irq_desc[irq].handler->end)
+ irq_desc[irq].handler->end(irq);
+ else if (irq_desc[irq].handler->enable)
+ irq_desc[irq].handler->enable(irq);
+ }
+ }
+
+ enable_irq(irq);
+ irq_exit(cpu, irq);
+
+ if (softirq_active(cpu) & softirq_mask(cpu))
+ do_softirq();
+
+ /* unmasking and bottom half handling is done magically for us. */
+}
+
+int request_irq(unsigned int irq,
+ void (*handler) (int, void *, struct pt_regs *),
+ unsigned long irqflags, const char *devname, void *dev_id)
+{
+ struct irqaction *old, **p, *action;
+ unsigned long flags;
+ if (irq >= NR_IRQS)
+ return -EINVAL;
+
+ action = (struct irqaction *)
+ kmalloc(sizeof(struct irqaction), GFP_KERNEL);
+ if (!action)
+ return -ENOMEM;
+
+ action->handler = handler;
+ action->flags = irqflags;
+ action->mask = 0;
+ action->name = devname;
+ action->dev_id = dev_id;
+ action->next = NULL;
+
+ save_flags(flags);
+ cli();
+
+ p = &irq_desc[irq].action;
+
+ if ((old = *p) != NULL) {
+ /* Can't share interrupts unless both agree to */
+ if (!(old->flags & action->flags & SA_SHIRQ))
+ return -EBUSY;
+ /* add new interrupt at end of irq queue */
+ do {
+ p = &old->next;
+ old = *p;
+ } while (old);
+ }
+ *p = action;
+
+ restore_flags(flags);
+ enable_irq(irq);
+
+ return 0;
+}
+
+
+void free_irq(unsigned int irq, void *dev_id)
+{
+ struct irqaction *p, *old = NULL;
+ unsigned long flags;
+ int count, tmp, removed = 0;
+
+ for (p = irq_desc[irq].action; p != NULL; old = p, p = p->next) {
+ /* Found the IRQ, is it the correct dev_id? */
+ if (dev_id == p->dev_id) {
+ save_flags(flags);
+ cli();
+
+ // remove link from list
+ if (old)
+ old->next = p->next;
+ else
+ irq_desc[irq].action = p->next;
+
+ restore_flags(flags);
+ kfree(p);
+ removed = 1;
+ break;
+ }
+ }
+}
+
+unsigned long probe_irq_on(void)
+{
+ printk(KERN_INFO "probe_irq_on\n");
+ return 0;
+}
+
+int probe_irq_off(unsigned long irqs)
+{
+ printk(KERN_INFO "probe_irq_off\n");
+ return 0;
+}
+
+void __init init_IRQ(void)
+{
+ int i;
+
+ DBG(KERN_INFO "rr:init_IRQ\n");
+
+ /* Let's initialize our IRQ descriptors */
+ for (i = 0; i < NR_IRQS; i++) {
+ irq_desc[i].status = 0;
+ irq_desc[i].handler = &no_irq_type;
+ irq_desc[i].action = NULL;
+ irq_desc[i].depth = 0;
+ irq_desc[i].lock = SPIN_LOCK_UNLOCKED;
+ }
+
+ irq_setup();
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 4
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -4
+ * c-argdecl-indent: 4
+ * c-label-offset: -4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: 0
+ * indent-tabs-mode: nil
+ * tab-width: 8
+ * End:
+ */
diff --git a/arch/mips/gt64120/common/pci.c b/arch/mips/gt64120/common/pci.c
new file mode 100644
index 000000000..d6b647e11
--- /dev/null
+++ b/arch/mips/gt64120/common/pci.c
@@ -0,0 +1,1140 @@
+/*
+ * BRIEF MODULE DESCRIPTION
+ * Galileo Evaluation Boards PCI support.
+ *
+ * The general-purpose functions to read/write and configure the GT64120A's
+ * PCI registers (function names start with pci0 or pci1) are either direct
+ * copies of functions written by Galileo Technology, or are modifications
+ * of their functions to work with Linux 2.4 vs Linux 2.2. These functions
+ * are Copyright - Galileo Technology.
+ *
+ * Other functions are derived from other MIPS PCI implementations, or were
+ * written by RidgeRun, Inc, Copyright (C) 2000 RidgeRun, Inc.
+ * glonnon@ridgerun.com, skranz@ridgerun.com, stevej@ridgerun.com
+ *
+ * Copyright 2001 MontaVista Software Inc.
+ * Author: Jun Sun, 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.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/malloc.h>
+#include <linux/version.h>
+#include <asm/pci.h>
+#include <asm/io.h>
+#include <asm/gt64120/gt64120.h>
+
+#include <linux/init.h>
+
+#ifdef CONFIG_PCI
+
+#define SELF 0
+
+/*
+ * These functions and structures provide the BIOS scan and mapping of the PCI
+ * devices.
+ */
+
+#define MAX_PCI_DEVS 10
+
+struct pci_device {
+ u32 slot;
+ u32 BARtype[6];
+ u32 BARsize[6];
+};
+
+static void __init scan_and_initialize_pci(void);
+static u32 __init scan_pci_bus(struct pci_device *pci_devices);
+static void __init allocate_pci_space(struct pci_device *pci_devices);
+
+/*
+ * The functions that actually read and write to the controller.
+ *
+ * Copied from or modified from Galileo Technology code.
+ */
+static unsigned int pci0ReadConfigReg(int offset, struct pci_dev *device);
+static void pci0WriteConfigReg(unsigned int offset,
+ struct pci_dev *device, unsigned int data);
+static unsigned int pci1ReadConfigReg(int offset, struct pci_dev *device);
+static void pci1WriteConfigReg(unsigned int offset,
+ struct pci_dev *device, unsigned int data);
+
+static void pci0MapIOspace(unsigned int pci0IoBase,
+ unsigned int pci0IoLength);
+static void pci1MapIOspace(unsigned int pci1IoBase,
+ unsigned int pci1IoLength);
+static void pci0MapMemory0space(unsigned int pci0Mem0Base,
+ unsigned int pci0Mem0Length);
+static void pci1MapMemory0space(unsigned int pci1Mem0Base,
+ unsigned int pci1Mem0Length);
+static void pci0MapMemory1space(unsigned int pci0Mem1Base,
+ unsigned int pci0Mem1Length);
+static void pci1MapMemory1space(unsigned int pci1Mem1Base,
+ unsigned int pci1Mem1Length);
+static unsigned int pci0GetIOspaceBase(void);
+static unsigned int pci0GetIOspaceSize(void);
+static unsigned int pci0GetMemory0Base(void);
+static unsigned int pci0GetMemory0Size(void);
+static unsigned int pci0GetMemory1Base(void);
+static unsigned int pci0GetMemory1Size(void);
+static unsigned int pci1GetIOspaceBase(void);
+static unsigned int pci1GetIOspaceSize(void);
+static unsigned int pci1GetMemory0Base(void);
+static unsigned int pci1GetMemory0Size(void);
+static unsigned int pci1GetMemory1Base(void);
+static unsigned int pci1GetMemory1Size(void);
+
+
+/* Functions to implement "pci ops" */
+static int galileo_pcibios_read_config_word(struct pci_dev *dev,
+ int offset, u16 * val);
+static int galileo_pcibios_read_config_byte(struct pci_dev *dev,
+ int offset, u8 * val);
+static int galileo_pcibios_read_config_dword(struct pci_dev *dev,
+ int offset, u32 * val);
+static int galileo_pcibios_write_config_byte(struct pci_dev *dev,
+ int offset, u8 val);
+static int galileo_pcibios_write_config_word(struct pci_dev *dev,
+ int offset, u16 val);
+static int galileo_pcibios_write_config_dword(struct pci_dev *dev,
+ int offset, u32 val);
+static void galileo_pcibios_set_master(struct pci_dev *dev);
+
+/*
+ * General-purpose PCI functions.
+ */
+
+/*
+ * pci0MapIOspace - Maps PCI0 IO space for the master.
+ * Inputs: base and length of pci0Io
+ */
+
+static void pci0MapIOspace(unsigned int pci0IoBase,
+ unsigned int pci0IoLength)
+{
+ unsigned int pci0IoTop =
+ (unsigned int) (pci0IoBase + pci0IoLength);
+
+ if (pci0IoLength == 0)
+ pci0IoTop++;
+
+ pci0IoBase = (unsigned int) (pci0IoBase >> 21);
+ pci0IoTop = (unsigned int) (((pci0IoTop - 1) & 0x0fffffff) >> 21);
+ GT_WRITE(GT_PCI0IOLD_OFS, pci0IoBase);
+ GT_WRITE(GT_PCI0IOHD_OFS, pci0IoTop);
+}
+
+/*
+ * pci1MapIOspace - Maps PCI1 IO space for the master.
+ * Inputs: base and length of pci1Io
+ */
+
+static void pci1MapIOspace(unsigned int pci1IoBase,
+ unsigned int pci1IoLength)
+{
+ unsigned int pci1IoTop =
+ (unsigned int) (pci1IoBase + pci1IoLength);
+
+ if (pci1IoLength == 0)
+ pci1IoTop++;
+
+ pci1IoBase = (unsigned int) (pci1IoBase >> 21);
+ pci1IoTop = (unsigned int) (((pci1IoTop - 1) & 0x0fffffff) >> 21);
+ GT_WRITE(GT_PCI1IOLD_OFS, pci1IoBase);
+ GT_WRITE(GT_PCI1IOHD_OFS, pci1IoTop);
+}
+
+/*
+ * pci0MapMemory0space - Maps PCI0 memory0 space for the master.
+ * Inputs: base and length of pci0Mem0
+ */
+
+static void pci0MapMemory0space(unsigned int pci0Mem0Base,
+ unsigned int pci0Mem0Length)
+{
+ unsigned int pci0Mem0Top = pci0Mem0Base + pci0Mem0Length;
+
+ if (pci0Mem0Length == 0)
+ pci0Mem0Top++;
+
+ pci0Mem0Base = pci0Mem0Base >> 21;
+ pci0Mem0Top = ((pci0Mem0Top - 1) & 0x0fffffff) >> 21;
+ GT_WRITE(GT_PCI0M0LD_OFS, pci0Mem0Base);
+ GT_WRITE(GT_PCI0M0HD_OFS, pci0Mem0Top);
+}
+
+/*
+ * pci1MapMemory0space - Maps PCI1 memory0 space for the master.
+ * Inputs: base and length of pci1Mem0
+ */
+
+static void pci1MapMemory0space(unsigned int pci1Mem0Base,
+ unsigned int pci1Mem0Length)
+{
+ unsigned int pci1Mem0Top = pci1Mem0Base + pci1Mem0Length;
+
+ if (pci1Mem0Length == 0)
+ pci1Mem0Top++;
+
+ pci1Mem0Base = pci1Mem0Base >> 21;
+ pci1Mem0Top = ((pci1Mem0Top - 1) & 0x0fffffff) >> 21;
+ GT_WRITE(GT_PCI1M0LD_OFS, pci1Mem0Base);
+ GT_WRITE(GT_PCI1M0HD_OFS, pci1Mem0Top);
+}
+
+/*
+ * pci0MapMemory1space - Maps PCI0 memory1 space for the master.
+ * Inputs: base and length of pci0Mem1
+ */
+
+static void pci0MapMemory1space(unsigned int pci0Mem1Base,
+ unsigned int pci0Mem1Length)
+{
+ unsigned int pci0Mem1Top = pci0Mem1Base + pci0Mem1Length;
+
+ if (pci0Mem1Length == 0)
+ pci0Mem1Top++;
+
+ pci0Mem1Base = pci0Mem1Base >> 21;
+ pci0Mem1Top = ((pci0Mem1Top - 1) & 0x0fffffff) >> 21;
+ GT_WRITE(GT_PCI0M1LD_OFS, pci0Mem1Base);
+ GT_WRITE(GT_PCI0M1HD_OFS, pci0Mem1Top);
+
+}
+
+/*
+ * pci1MapMemory1space - Maps PCI1 memory1 space for the master.
+ * Inputs: base and length of pci1Mem1
+ */
+
+static void pci1MapMemory1space(unsigned int pci1Mem1Base,
+ unsigned int pci1Mem1Length)
+{
+ unsigned int pci1Mem1Top = pci1Mem1Base + pci1Mem1Length;
+
+ if (pci1Mem1Length == 0)
+ pci1Mem1Top++;
+
+ pci1Mem1Base = pci1Mem1Base >> 21;
+ pci1Mem1Top = ((pci1Mem1Top - 1) & 0x0fffffff) >> 21;
+ GT_WRITE(GT_PCI1M1LD_OFS, pci1Mem1Base);
+ GT_WRITE(GT_PCI1M1HD_OFS, pci1Mem1Top);
+}
+
+/*
+ * pci0GetIOspaceBase - Return PCI0 IO Base Address.
+ * Inputs: N/A
+ * Returns: PCI0 IO Base Address.
+ */
+
+static unsigned int pci0GetIOspaceBase(void)
+{
+ unsigned int base;
+ GT_READ(GT_PCI0IOLD_OFS, &base);
+ base = base << 21;
+ return base;
+}
+
+/*
+ * pci0GetIOspaceSize - Return PCI0 IO Bar Size.
+ * Inputs: N/A
+ * Returns: PCI0 IO Bar Size.
+ */
+
+static unsigned int pci0GetIOspaceSize(void)
+{
+ unsigned int top, base, size;
+ GT_READ(GT_PCI0IOLD_OFS, &base);
+ base = base << 21;
+ GT_READ(GT_PCI0IOHD_OFS, &top);
+ top = (top << 21);
+ size = ((top - base) & 0xfffffff);
+ size = size | 0x1fffff;
+ return (size + 1);
+}
+
+/*
+ * pci0GetMemory0Base - Return PCI0 Memory 0 Base Address.
+ * Inputs: N/A
+ * Returns: PCI0 Memory 0 Base Address.
+ */
+
+static unsigned int pci0GetMemory0Base(void)
+{
+ unsigned int base;
+ GT_READ(GT_PCI0M0LD_OFS, &base);
+ base = base << 21;
+ return base;
+}
+
+/*
+ * pci0GetMemory0Size - Return PCI0 Memory 0 Bar Size.
+ * Inputs: N/A
+ * Returns: PCI0 Memory 0 Bar Size.
+ */
+
+static unsigned int pci0GetMemory0Size(void)
+{
+ unsigned int top, base, size;
+ GT_READ(GT_PCI0M0LD_OFS, &base);
+ base = base << 21;
+ GT_READ(GT_PCI0M0HD_OFS, &top);
+ top = (top << 21);
+ size = ((top - base) & 0xfffffff);
+ size = size | 0x1fffff;
+ return (size + 1);
+}
+
+/*
+ * pci0GetMemory1Base - Return PCI0 Memory 1 Base Address.
+ * Inputs: N/A
+ * Returns: PCI0 Memory 1 Base Address.
+ */
+
+static unsigned int pci0GetMemory1Base(void)
+{
+ unsigned int base;
+ GT_READ(GT_PCI0M1LD_OFS, &base);
+ base = base << 21;
+ return base;
+}
+
+/*
+ * pci0GetMemory1Size - Return PCI0 Memory 1 Bar Size.
+ * Inputs: N/A
+ * Returns: PCI0 Memory 1 Bar Size.
+ */
+
+static unsigned int pci0GetMemory1Size(void)
+{
+ unsigned int top, base, size;
+ GT_READ(GT_PCI0M1LD_OFS, &base);
+ base = base << 21;
+ GT_READ(GT_PCI0M1HD_OFS, &top);
+ top = (top << 21);
+ size = ((top - base) & 0xfffffff);
+ size = size | 0x1fffff;
+ return (size + 1);
+}
+
+/*
+ * pci1GetIOspaceBase - Return PCI1 IO Base Address.
+ * Inputs: N/A
+ * Returns: PCI1 IO Base Address.
+ */
+
+static unsigned int pci1GetIOspaceBase(void)
+{
+ unsigned int base;
+ GT_READ(GT_PCI1IOLD_OFS, &base);
+ base = base << 21;
+ return base;
+}
+
+/*
+ * pci1GetIOspaceSize - Return PCI1 IO Bar Size.
+ * Inputs: N/A
+ * Returns: PCI1 IO Bar Size.
+ */
+
+static unsigned int pci1GetIOspaceSize(void)
+{
+ unsigned int top, base, size;
+ GT_READ(GT_PCI1IOLD_OFS, &base);
+ base = base << 21;
+ GT_READ(GT_PCI1IOHD_OFS, &top);
+ top = (top << 21);
+ size = ((top - base) & 0xfffffff);
+ size = size | 0x1fffff;
+ return (size + 1);
+}
+
+/*
+ * pci1GetMemory0Base - Return PCI1 Memory 0 Base Address.
+ * Inputs: N/A
+ * Returns: PCI1 Memory 0 Base Address.
+ */
+
+static unsigned int pci1GetMemory0Base(void)
+{
+ unsigned int base;
+ GT_READ(GT_PCI1M0LD_OFS, &base);
+ base = base << 21;
+ return base;
+}
+
+/*
+ * pci1GetMemory0Size - Return PCI1 Memory 0 Bar Size.
+ * Inputs: N/A
+ * Returns: PCI1 Memory 0 Bar Size.
+ */
+
+static unsigned int pci1GetMemory0Size(void)
+{
+ unsigned int top, base, size;
+ GT_READ(GT_PCI1M1LD_OFS, &base);
+ base = base << 21;
+ GT_READ(GT_PCI1M1HD_OFS, &top);
+ top = (top << 21);
+ size = ((top - base) & 0xfffffff);
+ size = size | 0x1fffff;
+ return (size + 1);
+}
+
+/*
+ * pci1GetMemory1Base - Return PCI1 Memory 1 Base Address.
+ * Inputs: N/A
+ * Returns: PCI1 Memory 1 Base Address.
+ */
+
+static unsigned int pci1GetMemory1Base(void)
+{
+ unsigned int base;
+ GT_READ(GT_PCI1M1LD_OFS, &base);
+ base = base << 21;
+ return base;
+}
+
+/*
+ * pci1GetMemory1Size - Return PCI1 Memory 1 Bar Size.
+ * Inputs: N/A
+ * Returns: PCI1 Memory 1 Bar Size.
+ */
+
+static unsigned int pci1GetMemory1Size(void)
+{
+ unsigned int top, base, size;
+ GT_READ(GT_PCI1M1LD_OFS, &base);
+ base = base << 21;
+ GT_READ(GT_PCI1M1HD_OFS, &top);
+ top = (top << 21);
+ size = ((top - base) & 0xfffffff);
+ size = size | 0x1fffff;
+ return (size + 1);
+}
+
+
+
+/*
+ * pci_range_ck -
+ *
+ * Check if the pci device that are trying to access does really exists
+ * on the evaluation board.
+ *
+ * Inputs :
+ * bus - bus number (0 for PCI 0 ; 1 for PCI 1)
+ * dev - number of device on the specific pci bus
+ *
+ * Outpus :
+ * 0 - if OK , 1 - if failure
+ */
+static __inline__ int pci_range_ck(unsigned char bus, unsigned char dev)
+{
+ /*
+ * We don't even pretend to handle other busses than bus 0 correctly.
+ * Accessing device 31 crashes the CP7000 for some reason.
+ */
+ if ((bus == 0) && (dev != 31))
+ return 0;
+ return -1;
+}
+
+/*
+ * pciXReadConfigReg - Read from a PCI configuration register
+ * - Make sure the GT is configured as a master before
+ * reading from another device on the PCI.
+ * - The function takes care of Big/Little endian conversion.
+ * INPUTS: regOffset: The register offset as it apears in the GT spec (or PCI
+ * spec)
+ * pciDevNum: The device number needs to be addressed.
+ * RETURNS: data , if the data == 0xffffffff check the master abort bit in the
+ * cause register to make sure the data is valid
+ *
+ * Configuration Address 0xCF8:
+ *
+ * 31 30 24 23 16 15 11 10 8 7 2 0 <=bit Number
+ * |congif|Reserved| Bus |Device|Function|Register|00|
+ * |Enable| |Number|Number| Number | Number | | <=field Name
+ *
+ */
+static unsigned int pci0ReadConfigReg(int offset, struct pci_dev *device)
+{
+ unsigned int DataForRegCf8;
+ unsigned int data;
+
+ DataForRegCf8 = ((PCI_SLOT(device->devfn) << 11) |
+ (PCI_FUNC(device->devfn) << 8) |
+ (offset & ~0x3)) | 0x80000000;
+ GT_WRITE(GT_PCI0_CFGADDR_OFS, DataForRegCf8);
+
+ /*
+ * The casual observer might wonder why the READ is duplicated here,
+ * rather than immediately following the WRITE, and just have the swap
+ * in the "if". That's because there is a latency problem with trying
+ * to read immediately after setting up the address register. The "if"
+ * check gives enough time for the address to stabilize, so the READ
+ * can work.
+ */
+ if (PCI_SLOT(device->devfn) == SELF) { /* This board */
+ GT_READ(GT_PCI0_CFGDATA_OFS, &data);
+ return data;
+ } else { /* The PCI is working in LE Mode so swap the Data. */
+ GT_READ(GT_PCI0_CFGDATA_OFS, &data);
+ return cpu_to_le32(data);
+ }
+}
+
+static unsigned int pci1ReadConfigReg(int offset, struct pci_dev *device)
+{
+ unsigned int DataForRegCf8;
+ unsigned int data;
+
+ DataForRegCf8 = ((PCI_SLOT(device->devfn) << 11) |
+ (PCI_FUNC(device->devfn) << 8) |
+ (offset & ~0x3)) | 0x80000000;
+ /*
+ * The casual observer might wonder why the READ is duplicated here,
+ * rather than immediately following the WRITE, and just have the
+ * swap in the "if". That's because there is a latency problem
+ * with trying to read immediately after setting up the address
+ * register. The "if" check gives enough time for the address
+ * to stabilize, so the READ can work.
+ */
+ if (PCI_SLOT(device->devfn) == SELF) { /* This board */
+ /* when configurating our own PCI 1 L-unit the access is through
+ the PCI 0 interface with reg number = reg number + 0x80 */
+ DataForRegCf8 |= 0x80;
+ GT_WRITE(GT_PCI0_CFGADDR_OFS, DataForRegCf8);
+ } else { /* The PCI is working in LE Mode so swap the Data. */
+ GT_WRITE(GT_PCI1_CFGADDR_OFS, DataForRegCf8);
+ }
+ if (PCI_SLOT(device->devfn) == SELF) { /* This board */
+ GT_READ(GT_PCI0_CFGDATA_OFS, &data);
+ return data;
+ } else {
+ GT_READ(GT_PCI1_CFGDATA_OFS, &data);
+ return cpu_to_le32(data);
+ }
+}
+
+
+
+/*
+ * pciXWriteConfigReg - Write to a PCI configuration register
+ * - Make sure the GT is configured as a master before
+ * writingto another device on the PCI.
+ * - The function takes care of Big/Little endian conversion.
+ * Inputs: unsigned int regOffset: The register offset as it apears in the
+ * GT spec
+ * (or any other PCI device spec)
+ * pciDevNum: The device number needs to be addressed.
+ *
+ * Configuration Address 0xCF8:
+ *
+ * 31 30 24 23 16 15 11 10 8 7 2 0 <=bit Number
+ * |congif|Reserved| Bus |Device|Function|Register|00|
+ * |Enable| |Number|Number| Number | Number | | <=field Name
+ *
+ */
+static void pci0WriteConfigReg(unsigned int offset,
+ struct pci_dev *device, unsigned int data)
+{
+ unsigned int DataForRegCf8;
+
+ DataForRegCf8 = ((PCI_SLOT(device->devfn) << 11) |
+ (PCI_FUNC(device->devfn) << 8) |
+ (offset & ~0x3)) | 0x80000000;
+ GT_WRITE(GT_PCI0_CFGADDR_OFS, DataForRegCf8);
+ if (PCI_SLOT(device->devfn) == SELF) { /* This board */
+ GT_WRITE(GT_PCI0_CFGDATA_OFS, data);
+ } else { /* configuration Transaction over the pci. */
+ /* The PCI is working in LE Mode so swap the Data. */
+ GT_WRITE(GT_PCI0_CFGDATA_OFS, le32_to_cpu(data));
+ }
+}
+
+static void pci1WriteConfigReg(unsigned int offset,
+ struct pci_dev *device, unsigned int data)
+{
+ unsigned int DataForRegCf8;
+
+ DataForRegCf8 = ((PCI_SLOT(device->devfn) << 11) |
+ (PCI_FUNC(device->devfn) << 8) |
+ (offset & ~0x3)) | 0x80000000;
+ /*
+ * There is a latency problem
+ * with trying to read immediately after setting up the address
+ * register. The "if" check gives enough time for the address
+ * to stabilize, so the WRITE can work.
+ */
+ if (PCI_SLOT(device->devfn) == SELF) { /* This board */
+ /*
+ * when configurating our own PCI 1 L-unit the access is through
+ * the PCI 0 interface with reg number = reg number + 0x80
+ */
+ DataForRegCf8 |= 0x80;
+ GT_WRITE(GT_PCI0_CFGADDR_OFS, DataForRegCf8);
+ } else { /* configuration Transaction over the pci. */
+ /* The PCI is working in LE Mode so swap the Data. */
+ GT_WRITE(GT_PCI1_CFGADDR_OFS, DataForRegCf8);
+ }
+ if (PCI_SLOT(device->devfn) == SELF) { /* This board */
+ GT_WRITE(GT_PCI0_CFGDATA_OFS, data);
+ } else { /* configuration Transaction over the pci. */
+ GT_WRITE(GT_PCI1_CFGADDR_OFS, le32_to_cpu(data));
+ }
+}
+
+
+/*
+ * galileo_pcibios_(read/write)_config_(dword/word/byte) -
+ *
+ * reads/write a dword/word/byte register from the configuration space
+ * of a device.
+ *
+ * Inputs :
+ * bus - bus number
+ * dev - device number
+ * offset - register offset in the configuration space
+ * val - value to be written / read
+ *
+ * Outputs :
+ * PCIBIOS_SUCCESSFUL when operation was succesfull
+ * PCIBIOS_DEVICE_NOT_FOUND when the bus or dev is errorneous
+ * PCIBIOS_BAD_REGISTER_NUMBER when accessing non aligned
+ */
+
+static int galileo_pcibios_read_config_dword(struct pci_dev *device,
+ int offset, u32 * val)
+{
+ int dev, bus;
+ bus = device->bus->number;
+ dev = PCI_SLOT(device->devfn);
+
+ if (pci_range_ck(bus, dev)) {
+ *val = 0xffffffff;
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ }
+ if (offset & 0x3)
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+ if (bus == 0)
+ *val = pci0ReadConfigReg(offset, device);
+
+ /* This is so that the upper PCI layer will get the correct return value if
+ we're not attached to anything. */
+ if ((offset == 0) && (*val == 0xffffffff)) {
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ }
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int galileo_pcibios_read_config_word(struct pci_dev *device,
+ int offset, u16 * val)
+{
+ int dev, bus;
+
+ bus = device->bus->number;
+ dev = PCI_SLOT(device->devfn);
+
+ if (pci_range_ck(bus, dev)) {
+ *val = 0xffff;
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ }
+ if (offset & 0x1)
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+
+ if (bus == 0)
+ *val =
+ (unsigned short) (pci0ReadConfigReg(offset, device) >>
+ ((offset & ~0x3) * 8));
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int galileo_pcibios_read_config_byte(struct pci_dev *device,
+ int offset, u8 * val)
+{
+ int dev, bus;
+
+ bus = device->bus->number;
+ dev = PCI_SLOT(device->devfn);
+
+ if (pci_range_ck(bus, dev)) {
+ *val = 0xff;
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ }
+
+ if (bus == 0)
+ *val =
+ (unsigned char) (pci0ReadConfigReg(offset, device) >>
+ ((offset & ~0x3) * 8));
+
+ /*
+ * This is so that the upper PCI layer will get the correct return
+ * value if we're not attached to anything.
+ */
+ if ((offset == 0xe) && (*val == 0xff)) {
+ u32 MasterAbort;
+ GT_READ(GT_INTRCAUSE_OFS, &MasterAbort);
+ if (MasterAbort & 0x40000) {
+ GT_WRITE(GT_INTRCAUSE_OFS,
+ (MasterAbort & 0xfffbffff));
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ }
+ }
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int galileo_pcibios_write_config_dword(struct pci_dev *device,
+ int offset, u32 val)
+{
+ int dev, bus;
+
+ bus = device->bus->number;
+ dev = PCI_SLOT(device->devfn);
+
+ if (pci_range_ck(bus, dev))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ if (offset & 0x3)
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+ if (bus == 0)
+ pci0WriteConfigReg(offset, device, val);
+// if (bus == 1) pci1WriteConfigReg (offset,device,val);
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+
+static int galileo_pcibios_write_config_word(struct pci_dev *device,
+ int offset, u16 val)
+{
+ int dev, bus;
+ unsigned long tmp;
+
+ bus = device->bus->number;
+ dev = PCI_SLOT(device->devfn);
+
+ if (pci_range_ck(bus, dev))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ if (offset & 0x1)
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+ if (bus == 0)
+ tmp = pci0ReadConfigReg(offset, device);
+// if (bus == 1) tmp = pci1ReadConfigReg (offset,device);
+
+ if ((offset % 4) == 0)
+ tmp = (tmp & 0xffff0000) | (val & 0xffff);
+ if ((offset % 4) == 2)
+ tmp = (tmp & 0x0000ffff) | ((val & 0xffff) << 16);
+
+ if (bus == 0)
+ pci0WriteConfigReg(offset, device, tmp);
+// if (bus == 1) pci1WriteConfigReg (offset,device,tmp);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int galileo_pcibios_write_config_byte(struct pci_dev *device,
+ int offset, u8 val)
+{
+ int dev, bus;
+ unsigned long tmp;
+
+ bus = device->bus->number;
+ dev = PCI_SLOT(device->devfn);
+
+ if (pci_range_ck(bus, dev))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ if (bus == 0)
+ tmp = pci0ReadConfigReg(offset, device);
+// if (bus == 1) tmp = pci1ReadConfigReg (offset,device);
+
+ if ((offset % 4) == 0)
+ tmp = (tmp & 0xffffff00) | (val & 0xff);
+ if ((offset % 4) == 1)
+ tmp = (tmp & 0xffff00ff) | ((val & 0xff) << 8);
+ if ((offset % 4) == 2)
+ tmp = (tmp & 0xff00ffff) | ((val & 0xff) << 16);
+ if ((offset % 4) == 3)
+ tmp = (tmp & 0x00ffffff) | ((val & 0xff) << 24);
+
+ if (bus == 0)
+ pci0WriteConfigReg(offset, device, tmp);
+// if (bus == 1) pci1WriteConfigReg (offset,device,tmp);
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static void galileo_pcibios_set_master(struct pci_dev *dev)
+{
+ u16 cmd;
+
+ galileo_pcibios_read_config_word(dev, PCI_COMMAND, &cmd);
+ cmd |= PCI_COMMAND_MASTER;
+ galileo_pcibios_write_config_word(dev, PCI_COMMAND, cmd);
+}
+
+/* Externally-expected functions. Do not change function names */
+
+int pcibios_enable_resources(struct pci_dev *dev)
+{
+ u16 cmd, old_cmd;
+ u8 tmp1;
+ int idx;
+ struct resource *r;
+
+ galileo_pcibios_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) {
+ galileo_pcibios_write_config_word(dev, PCI_COMMAND, cmd);
+ }
+
+ /*
+ * Let's fix up the latency timer and cache line size here. Cache
+ * line size = 32 bytes / sizeof dword (4) = 8.
+ * Latency timer must be > 8. 32 is random but appears to work.
+ */
+ galileo_pcibios_read_config_byte(dev, PCI_CACHE_LINE_SIZE, &tmp1);
+ if (tmp1 != 8) {
+ printk(KERN_WARNING "PCI setting cache line size to 8 from "
+ "%d\n", tmp1);
+ galileo_pcibios_write_config_byte(dev, PCI_CACHE_LINE_SIZE,
+ 8);
+ }
+ galileo_pcibios_read_config_byte(dev, PCI_LATENCY_TIMER, &tmp1);
+ if (tmp1 < 32) {
+ printk(KERN_WARNING "PCI setting latency timer to 32 from %d\n",
+ tmp1);
+ galileo_pcibios_write_config_byte(dev, PCI_LATENCY_TIMER,
+ 32);
+ }
+
+ return 0;
+}
+
+int pcibios_enable_device(struct pci_dev *dev)
+{
+ return pcibios_enable_resources(dev);
+}
+
+void pcibios_update_resource(struct pci_dev *dev, struct resource *root,
+ struct resource *res, int resource)
+{
+ u32 new, check;
+ int reg;
+
+ return;
+
+ new = res->start | (res->flags & PCI_REGION_FLAG_MASK);
+ if (resource < 6) {
+ reg = PCI_BASE_ADDRESS_0 + 4 * resource;
+ } else if (resource == PCI_ROM_RESOURCE) {
+ res->flags |= PCI_ROM_ADDRESS_ENABLE;
+ reg = dev->rom_base_reg;
+ } else {
+ /*
+ * Somebody might have asked allocation of a non-standard
+ * resource
+ */
+ return;
+ }
+
+ pci_write_config_dword(dev, reg, new);
+ pci_read_config_dword(dev, reg, &check);
+ if ((new ^ check) &
+ ((new & PCI_BASE_ADDRESS_SPACE_IO) ? PCI_BASE_ADDRESS_IO_MASK :
+ PCI_BASE_ADDRESS_MEM_MASK)) {
+ printk(KERN_ERR "PCI: Error while updating region "
+ "%s/%d (%08x != %08x)\n", dev->slot_name, resource,
+ new, check);
+ }
+}
+
+void pcibios_align_resource(void *data, struct resource *res,
+ unsigned long size)
+{
+ 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;
+ }
+}
+
+struct pci_ops galileo_pci_ops = {
+ galileo_pcibios_read_config_byte,
+ galileo_pcibios_read_config_word,
+ galileo_pcibios_read_config_dword,
+ galileo_pcibios_write_config_byte,
+ galileo_pcibios_write_config_word,
+ galileo_pcibios_write_config_dword
+};
+
+struct pci_fixup pcibios_fixups[] = {
+ {0}
+};
+
+void __init pcibios_fixup_bus(struct pci_bus *c)
+{
+ gt64120_board_pcibios_fixup_bus(c);
+}
+
+/*
+ * This code was derived from Galileo Technology's example
+ * and significantly reworked.
+ *
+ * This is very simple. It does not scan multiple function devices. It does
+ * not scan behind bridges. Those would be simple to implement, but we don't
+ * currently need this.
+ */
+
+static void __init scan_and_initialize_pci(void)
+{
+ struct pci_device pci_devices[MAX_PCI_DEVS];
+
+ if (scan_pci_bus(pci_devices)) {
+ allocate_pci_space(pci_devices);
+ }
+}
+
+/*
+ * This is your basic PCI scan. It goes through each slot and checks to
+ * see if there's something that responds. If so, then get the size and
+ * type of each of the responding BARs. Save them for later.
+ */
+
+static u32 __init scan_pci_bus(struct pci_device *pci_devices)
+{
+ u32 arrayCounter = 0;
+ u32 memType;
+ u32 memSize;
+ u32 pci_slot, bar;
+ u32 id;
+ u32 c18RegValue;
+ struct pci_dev device;
+
+ /*
+ * According to PCI REV 2.1 MAX agents on the bus are 21.
+ * We don't bother scanning ourselves (slot 0).
+ */
+ for (pci_slot = 1; pci_slot < 22; pci_slot++) {
+
+ device.devfn = PCI_DEVFN(pci_slot, 0);
+ id = pci0ReadConfigReg(PCI_VENDOR_ID, &device);
+
+ /*
+ * Check for a PCI Master Abort (nothing responds in the
+ * slot)
+ */
+ GT_READ(GT_INTRCAUSE_OFS, &c18RegValue);
+ /*
+ * Clearing bit 18 of in the Cause Register 0xc18 by
+ * writting 0.
+ */
+ GT_WRITE(GT_INTRCAUSE_OFS, (c18RegValue & 0xfffbffff));
+ if ((id != 0xffffffff) && !(c18RegValue & 0x40000)) {
+ pci_devices[arrayCounter].slot = pci_slot;
+ for (bar = 0; bar < 6; bar++) {
+ memType =
+ pci0ReadConfigReg(PCI_BASE_ADDRESS_0 +
+ (bar * 4), &device);
+ pci_devices[arrayCounter].BARtype[bar] =
+ memType & 1;
+ pci0WriteConfigReg(PCI_BASE_ADDRESS_0 +
+ (bar * 4), &device,
+ 0xffffffff);
+ memSize =
+ pci0ReadConfigReg(PCI_BASE_ADDRESS_0 +
+ (bar * 4), &device);
+ if (memType & 1) { /* IO space */
+ pci_devices[arrayCounter].
+ BARsize[bar] =
+ ~(memSize & 0xfffffffc) + 1;
+ } else { /* memory space */
+ pci_devices[arrayCounter].
+ BARsize[bar] =
+ ~(memSize & 0xfffffff0) + 1;
+ }
+ } /* BAR counter */
+
+ arrayCounter++;
+ }
+ /* found a device */
+ } /* slot counter */
+
+ if (arrayCounter < MAX_PCI_DEVS)
+ pci_devices[arrayCounter].slot = -1;
+
+ return arrayCounter;
+}
+
+#define ALIGN(val,align) (((val) + ((align) - 1)) & ~((align) - 1))
+#define MAX(val1, val2) ((val1) > (val2) ? (val1) : (val2))
+
+/*
+ * This function goes through the list of devices and allocates the BARs in
+ * either IO or MEM space. It does it in order of size, which will limit the
+ * amount of fragmentation we have in the IO and MEM spaces.
+ */
+
+static void __init allocate_pci_space(struct pci_device *pci_devices)
+{
+ u32 count, maxcount, bar;
+ u32 maxSize, maxDevice, maxBAR;
+ u32 alignto;
+ u32 base;
+ u32 pci0_mem_base = pci0GetMemory0Base();
+ u32 pci0_io_base = pci0GetIOspaceBase();
+ struct pci_dev device;
+
+ /* How many PCI devices do we have? */
+ maxcount = MAX_PCI_DEVS;
+ for (count = 0; count < MAX_PCI_DEVS; count++) {
+ if (pci_devices[count].slot == -1) {
+ maxcount = count;
+ break;
+ }
+ }
+
+ do {
+ /* Find the largest size BAR we need to allocate */
+ maxSize = 0;
+ for (count = 0; count < maxcount; count++) {
+ for (bar = 0; bar < 6; bar++) {
+ if (pci_devices[count].BARsize[bar] >
+ maxSize) {
+ maxSize =
+ pci_devices[count].
+ BARsize[bar];
+ maxDevice = count;
+ maxBAR = bar;
+ }
+ }
+ }
+
+ /*
+ * We've found the largest BAR. Allocate it into IO or
+ * mem space. We don't idiot check the bases to make
+ * sure they haven't overflowed the current size for that
+ * aperture.
+ * Don't bother to enable the device's IO or MEM space here.
+ * That will be done in pci_enable_resources if the device is
+ * activated by a driver.
+ */
+ if (maxSize) {
+ device.devfn =
+ PCI_DEVFN(pci_devices[maxDevice].slot, 0);
+ if (pci_devices[maxDevice].BARtype[maxBAR] == 1) {
+ alignto = MAX(0x1000, maxSize);
+ base = ALIGN(pci0_io_base, alignto);
+ pci0WriteConfigReg(PCI_BASE_ADDRESS_0 +
+ (maxBAR * 4), &device,
+ base | 0x1);
+ pci0_io_base = base + alignto;
+ } else {
+ alignto = MAX(0x1000, maxSize);
+ base = ALIGN(pci0_mem_base, alignto);
+ pci0WriteConfigReg(PCI_BASE_ADDRESS_0 +
+ (maxBAR * 4), &device,
+ base);
+ pci0_mem_base = base + alignto;
+ }
+ /*
+ * This entry is finished. Remove it from the list
+ * we'll scan.
+ */
+ pci_devices[maxDevice].BARsize[maxBAR] = 0;
+ }
+ } while (maxSize);
+}
+
+void __init pcibios_init(void)
+{
+ u32 tmp;
+ struct pci_dev controller;
+
+ controller.devfn = SELF;
+
+ GT_READ(GT_PCI0_CMD_OFS, &tmp);
+ GT_READ(GT_PCI0_BARE_OFS, &tmp);
+
+ /*
+ * You have to enable bus mastering to configure any other
+ * card on the bus.
+ */
+ tmp = pci0ReadConfigReg(PCI_COMMAND, &controller);
+ tmp |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_SERR;
+ pci0WriteConfigReg(PCI_COMMAND, &controller, tmp);
+
+ /* This scans the PCI bus and sets up initial values. */
+ // scan_and_initialize_pci();
+
+ /*
+ * Reset PCI I/O and PCI MEM values to ones supported by EVM.
+ */
+ ioport_resource.start = 0x10000000;
+ ioport_resource.end = 0x11ffffff; /* 32 MB */
+ iomem_resource.start = 0x12000000;
+ iomem_resource.end = 0x13ffffff; /* 32 MB */
+
+ pci_scan_bus(0, &galileo_pci_ops, NULL);
+}
+
+/*
+ * for parsing "pci=" kernel boot arguments.
+ */
+char *pcibios_setup(char *str)
+{
+ printk(KERN_INFO "rr: pcibios_setup\n");
+ /* Nothing to do for now. */
+
+ return str;
+}
+
+#endif /* CONFIG_PCI */