summaryrefslogtreecommitdiffstats
path: root/arch/mips/gt64120/common
diff options
context:
space:
mode:
Diffstat (limited to 'arch/mips/gt64120/common')
-rw-r--r--arch/mips/gt64120/common/Makefile6
-rw-r--r--arch/mips/gt64120/common/pci.c147
-rw-r--r--arch/mips/gt64120/common/time.c100
3 files changed, 253 insertions, 0 deletions
diff --git a/arch/mips/gt64120/common/Makefile b/arch/mips/gt64120/common/Makefile
new file mode 100644
index 00000000000..eba5051015a
--- /dev/null
+++ b/arch/mips/gt64120/common/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for common code of gt64120-based boards.
+#
+
+obj-y += time.o
+obj-$(CONFIG_PCI) += pci.o
diff --git a/arch/mips/gt64120/common/pci.c b/arch/mips/gt64120/common/pci.c
new file mode 100644
index 00000000000..e9e5419a0d5
--- /dev/null
+++ b/arch/mips/gt64120/common/pci.c
@@ -0,0 +1,147 @@
+/*
+ * 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
+ *
+ * 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/init.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <asm/gt64120.h>
+
+#define SELF 0
+
+/*
+ * 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 */
+ return GT_READ(GT_PCI0_CFGDATA_OFS);
+ else /* PCI is little endian so swap the Data. */
+ return __GT_READ(GT_PCI0_CFGDATA_OFS);
+}
+
+/*
+ * 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. */
+ __GT_WRITE(GT_PCI0_CFGDATA_OFS, data);
+}
+
+extern struct pci_ops gt64120_pci_ops;
+
+void __init pcibios_init(void)
+{
+ u32 tmp;
+ struct pci_dev controller;
+
+ controller.devfn = SELF;
+
+ tmp = GT_READ(GT_PCI0_CMD_OFS); /* Huh??? -- Ralf */
+ tmp = GT_READ(GT_PCI0_BARE_OFS);
+
+ /*
+ * 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);
+
+ /*
+ * Reset PCI I/O and PCI MEM values to ones supported by EVM.
+ */
+ ioport_resource.start = GT_PCI_IO_BASE;
+ ioport_resource.end = GT_PCI_IO_BASE + GT_PCI_IO_SIZE - 1;
+ iomem_resource.start = GT_PCI_MEM_BASE;
+ iomem_resource.end = GT_PCI_MEM_BASE + GT_PCI_MEM_SIZE - 1;
+
+ pci_scan_bus(0, &gt64120_pci_ops, NULL);
+}
diff --git a/arch/mips/gt64120/common/time.c b/arch/mips/gt64120/common/time.c
new file mode 100644
index 00000000000..2287b59536e
--- /dev/null
+++ b/arch/mips/gt64120/common/time.c
@@ -0,0 +1,100 @@
+/*
+ * 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.
+ *
+ * Galileo Technology chip interrupt handler
+ */
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/config.h>
+#include <linux/sched.h>
+#include <linux/kernel_stat.h>
+#include <asm/ptrace.h>
+#include <asm/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.
+ */
+
+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 = 0;
+
+ irq_src = GT_READ(GT_INTRCAUSE_OFS);
+ irq_src_mask = GT_READ(GT_INTRMASK_OFS);
+ int_high_src = GT_READ(GT_HINTRCAUSE_OFS);
+ int_high_src_mask = GT_READ(GT_HINTRMASK_OFS);
+ irq_src = irq_src & irq_src_mask;
+ int_high_src = int_high_src & int_high_src_mask;
+
+ if (irq_src & 0x00000800) { /* Check for timer interrupt */
+ handled = 1;
+ irq_src &= ~0x00000800;
+ do_timer(regs);
+#ifndef CONFIG_SMP
+ update_process_times(user_mode(regs));
+#endif
+ }
+
+ GT_WRITE(GT_INTRCAUSE_OFS, 0);
+ GT_WRITE(GT_HINTRCAUSE_OFS, 0);
+}
+
+/*
+ * 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(void)
+{
+ 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 = CPU_MASK_NONE;
+ irq_desc[GT_TIMER].action = &timer;
+
+ enable_irq(GT_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);
+}