summaryrefslogtreecommitdiffstats
path: root/arch/mips/txx9/generic
diff options
context:
space:
mode:
Diffstat (limited to 'arch/mips/txx9/generic')
-rw-r--r--arch/mips/txx9/generic/Makefile12
-rw-r--r--arch/mips/txx9/generic/dbgio.c48
-rw-r--r--arch/mips/txx9/generic/irq_tx4927.c37
-rw-r--r--arch/mips/txx9/generic/irq_tx4938.c25
-rw-r--r--arch/mips/txx9/generic/mem_tx4927.c141
-rw-r--r--arch/mips/txx9/generic/mem_tx4938.c124
-rw-r--r--arch/mips/txx9/generic/pci.c388
-rw-r--r--arch/mips/txx9/generic/setup.c212
-rw-r--r--arch/mips/txx9/generic/smsc_fdc37m81x.c172
9 files changed, 1159 insertions, 0 deletions
diff --git a/arch/mips/txx9/generic/Makefile b/arch/mips/txx9/generic/Makefile
new file mode 100644
index 0000000..668fdaa
--- /dev/null
+++ b/arch/mips/txx9/generic/Makefile
@@ -0,0 +1,12 @@
+#
+# Makefile for common code for TXx9 based systems
+#
+
+obj-y += setup.o
+obj-$(CONFIG_PCI) += pci.o
+obj-$(CONFIG_SOC_TX4927) += mem_tx4927.o irq_tx4927.o
+obj-$(CONFIG_SOC_TX4938) += mem_tx4938.o irq_tx4938.o
+obj-$(CONFIG_TOSHIBA_FPCIB0) += smsc_fdc37m81x.o
+obj-$(CONFIG_KGDB) += dbgio.o
+
+EXTRA_CFLAGS += -Werror
diff --git a/arch/mips/txx9/generic/dbgio.c b/arch/mips/txx9/generic/dbgio.c
new file mode 100644
index 0000000..33b9c67
--- /dev/null
+++ b/arch/mips/txx9/generic/dbgio.c
@@ -0,0 +1,48 @@
+/*
+ * linux/arch/mips/tx4938/common/dbgio.c
+ *
+ * kgdb interface for gdb
+ *
+ * Author: MontaVista Software, Inc.
+ * source@mvista.com
+ *
+ * Copyright 2005 MontaVista Software Inc.
+ *
+ * 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.
+ *
+ * Support for TX4938 in 2.6 - Hiroshi DOYU <Hiroshi_DOYU@montavista.co.jp>
+ */
+
+#include <linux/types>
+
+extern u8 txx9_sio_kdbg_rd(void);
+extern int txx9_sio_kdbg_wr( u8 ch );
+
+u8 getDebugChar(void)
+{
+ return (txx9_sio_kdbg_rd());
+}
+
+int putDebugChar(u8 byte)
+{
+ return (txx9_sio_kdbg_wr(byte));
+}
+
diff --git a/arch/mips/txx9/generic/irq_tx4927.c b/arch/mips/txx9/generic/irq_tx4927.c
new file mode 100644
index 0000000..6377bd8
--- /dev/null
+++ b/arch/mips/txx9/generic/irq_tx4927.c
@@ -0,0 +1,37 @@
+/*
+ * Common tx4927 irq handler
+ *
+ * Author: MontaVista Software, Inc.
+ * source@mvista.com
+ *
+ * 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/interrupt.h>
+#include <asm/irq_cpu.h>
+#include <asm/txx9/tx4927.h>
+
+void __init tx4927_irq_init(void)
+{
+ mips_cpu_irq_init();
+ txx9_irq_init(TX4927_IRC_REG);
+ set_irq_chained_handler(MIPS_CPU_IRQ_BASE + TX4927_IRC_INT,
+ handle_simple_irq);
+}
diff --git a/arch/mips/txx9/generic/irq_tx4938.c b/arch/mips/txx9/generic/irq_tx4938.c
new file mode 100644
index 0000000..5fc86c9
--- /dev/null
+++ b/arch/mips/txx9/generic/irq_tx4938.c
@@ -0,0 +1,25 @@
+/*
+ * linux/arch/mips/tx4938/common/irq.c
+ *
+ * Common tx4938 irq handler
+ * Copyright (C) 2000-2001 Toshiba Corporation
+ *
+ * 2003-2005 (c) MontaVista Software, Inc. This file is licensed under the
+ * terms of the GNU General Public License version 2. This program is
+ * licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ *
+ * Support for TX4938 in 2.6 - Manish Lachwani (mlachwani@mvista.com)
+ */
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <asm/irq_cpu.h>
+#include <asm/txx9/tx4938.h>
+
+void __init tx4938_irq_init(void)
+{
+ mips_cpu_irq_init();
+ txx9_irq_init(TX4938_IRC_REG);
+ set_irq_chained_handler(MIPS_CPU_IRQ_BASE + TX4938_IRC_INT,
+ handle_simple_irq);
+}
diff --git a/arch/mips/txx9/generic/mem_tx4927.c b/arch/mips/txx9/generic/mem_tx4927.c
new file mode 100644
index 0000000..12dfc37
--- /dev/null
+++ b/arch/mips/txx9/generic/mem_tx4927.c
@@ -0,0 +1,141 @@
+/*
+ * linux/arch/mips/tx4927/common/tx4927_prom.c
+ *
+ * common tx4927 memory interface
+ *
+ * Author: MontaVista Software, Inc.
+ * source@mvista.com
+ *
+ * Copyright 2001-2002 MontaVista Software Inc.
+ *
+ * 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/io.h>
+
+static unsigned int __init tx4927_process_sdccr(unsigned long addr)
+{
+ u64 val;
+ unsigned int sdccr_ce;
+ unsigned int sdccr_bs;
+ unsigned int sdccr_rs;
+ unsigned int sdccr_cs;
+ unsigned int sdccr_mw;
+ unsigned int bs = 0;
+ unsigned int rs = 0;
+ unsigned int cs = 0;
+ unsigned int mw = 0;
+ unsigned int msize = 0;
+
+ val = __raw_readq((void __iomem *)addr);
+
+ /* MVMCP -- need #defs for these bits masks */
+ sdccr_ce = ((val & (1 << 10)) >> 10);
+ sdccr_bs = ((val & (1 << 8)) >> 8);
+ sdccr_rs = ((val & (3 << 5)) >> 5);
+ sdccr_cs = ((val & (3 << 2)) >> 2);
+ sdccr_mw = ((val & (1 << 0)) >> 0);
+
+ if (sdccr_ce) {
+ switch (sdccr_bs) {
+ case 0:{
+ bs = 2;
+ break;
+ }
+ case 1:{
+ bs = 4;
+ break;
+ }
+ }
+ switch (sdccr_rs) {
+ case 0:{
+ rs = 2048;
+ break;
+ }
+ case 1:{
+ rs = 4096;
+ break;
+ }
+ case 2:{
+ rs = 8192;
+ break;
+ }
+ case 3:{
+ rs = 0;
+ break;
+ }
+ }
+ switch (sdccr_cs) {
+ case 0:{
+ cs = 256;
+ break;
+ }
+ case 1:{
+ cs = 512;
+ break;
+ }
+ case 2:{
+ cs = 1024;
+ break;
+ }
+ case 3:{
+ cs = 2048;
+ break;
+ }
+ }
+ switch (sdccr_mw) {
+ case 0:{
+ mw = 8;
+ break;
+ } /* 8 bytes = 64 bits */
+ case 1:{
+ mw = 4;
+ break;
+ } /* 4 bytes = 32 bits */
+ }
+ }
+
+ /* bytes per chip MB per chip num chips */
+ msize = (((rs * cs * mw) / (1024 * 1024)) * bs);
+
+ return (msize);
+}
+
+
+unsigned int __init tx4927_get_mem_size(void)
+{
+ unsigned int c0;
+ unsigned int c1;
+ unsigned int c2;
+ unsigned int c3;
+ unsigned int total;
+
+ /* MVMCP -- need #defs for these registers */
+ c0 = tx4927_process_sdccr(0xff1f8000);
+ c1 = tx4927_process_sdccr(0xff1f8008);
+ c2 = tx4927_process_sdccr(0xff1f8010);
+ c3 = tx4927_process_sdccr(0xff1f8018);
+ total = c0 + c1 + c2 + c3;
+
+ return (total);
+}
diff --git a/arch/mips/txx9/generic/mem_tx4938.c b/arch/mips/txx9/generic/mem_tx4938.c
new file mode 100644
index 0000000..20baeae
--- /dev/null
+++ b/arch/mips/txx9/generic/mem_tx4938.c
@@ -0,0 +1,124 @@
+/*
+ * linux/arch/mips/tx4938/common/prom.c
+ *
+ * common tx4938 memory interface
+ * Copyright (C) 2000-2001 Toshiba Corporation
+ *
+ * 2003-2005 (c) MontaVista Software, Inc. This file is licensed under the
+ * terms of the GNU General Public License version 2. This program is
+ * licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ *
+ * Support for TX4938 in 2.6 - Manish Lachwani (mlachwani@mvista.com)
+ */
+
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/io.h>
+
+static unsigned int __init
+tx4938_process_sdccr(u64 * addr)
+{
+ u64 val;
+ unsigned int sdccr_ce;
+ unsigned int sdccr_rs;
+ unsigned int sdccr_cs;
+ unsigned int sdccr_mw;
+ unsigned int rs = 0;
+ unsigned int cs = 0;
+ unsigned int mw = 0;
+ unsigned int bc = 4;
+ unsigned int msize = 0;
+
+ val = ____raw_readq((void __iomem *)addr);
+
+ /* MVMCP -- need #defs for these bits masks */
+ sdccr_ce = ((val & (1 << 10)) >> 10);
+ sdccr_rs = ((val & (3 << 5)) >> 5);
+ sdccr_cs = ((val & (7 << 2)) >> 2);
+ sdccr_mw = ((val & (1 << 0)) >> 0);
+
+ if (sdccr_ce) {
+ switch (sdccr_rs) {
+ case 0:{
+ rs = 2048;
+ break;
+ }
+ case 1:{
+ rs = 4096;
+ break;
+ }
+ case 2:{
+ rs = 8192;
+ break;
+ }
+ default:{
+ rs = 0;
+ break;
+ }
+ }
+ switch (sdccr_cs) {
+ case 0:{
+ cs = 256;
+ break;
+ }
+ case 1:{
+ cs = 512;
+ break;
+ }
+ case 2:{
+ cs = 1024;
+ break;
+ }
+ case 3:{
+ cs = 2048;
+ break;
+ }
+ case 4:{
+ cs = 4096;
+ break;
+ }
+ default:{
+ cs = 0;
+ break;
+ }
+ }
+ switch (sdccr_mw) {
+ case 0:{
+ mw = 8;
+ break;
+ } /* 8 bytes = 64 bits */
+ case 1:{
+ mw = 4;
+ break;
+ } /* 4 bytes = 32 bits */
+ }
+ }
+
+ /* bytes per chip MB per chip bank count */
+ msize = (((rs * cs * mw) / (1024 * 1024)) * (bc));
+
+ /* MVMCP -- bc hard coded to 4 from table 9.3.1 */
+ /* boad supports bc=2 but no way to detect */
+
+ return (msize);
+}
+
+unsigned int __init
+tx4938_get_mem_size(void)
+{
+ unsigned int c0;
+ unsigned int c1;
+ unsigned int c2;
+ unsigned int c3;
+ unsigned int total;
+
+ /* MVMCP -- need #defs for these registers */
+ c0 = tx4938_process_sdccr((u64 *) 0xff1f8000);
+ c1 = tx4938_process_sdccr((u64 *) 0xff1f8008);
+ c2 = tx4938_process_sdccr((u64 *) 0xff1f8010);
+ c3 = tx4938_process_sdccr((u64 *) 0xff1f8018);
+ total = c0 + c1 + c2 + c3;
+
+ return (total);
+}
diff --git a/arch/mips/txx9/generic/pci.c b/arch/mips/txx9/generic/pci.c
new file mode 100644
index 0000000..0b92d8c
--- /dev/null
+++ b/arch/mips/txx9/generic/pci.c
@@ -0,0 +1,388 @@
+/*
+ * linux/arch/mips/txx9/pci.c
+ *
+ * Based on linux/arch/mips/txx9/rbtx4927/setup.c,
+ * linux/arch/mips/txx9/rbtx4938/setup.c,
+ * and RBTX49xx patch from CELF patch archive.
+ *
+ * Copyright 2001-2005 MontaVista Software Inc.
+ * Copyright (C) 1996, 97, 2001, 04 Ralf Baechle (ralf@linux-mips.org)
+ * (C) Copyright TOSHIBA CORPORATION 2000-2001, 2004-2007
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/delay.h>
+#include <linux/jiffies.h>
+#include <linux/io.h>
+#include <asm/txx9/generic.h>
+#include <asm/txx9/pci.h>
+#ifdef CONFIG_TOSHIBA_FPCIB0
+#include <linux/interrupt.h>
+#include <asm/i8259.h>
+#include <asm/txx9/smsc_fdc37m81x.h>
+#endif
+
+static int __init
+early_read_config_word(struct pci_controller *hose,
+ int top_bus, int bus, int devfn, int offset, u16 *value)
+{
+ struct pci_dev fake_dev;
+ struct pci_bus fake_bus;
+
+ fake_dev.bus = &fake_bus;
+ fake_dev.sysdata = hose;
+ fake_dev.devfn = devfn;
+ fake_bus.number = bus;
+ fake_bus.sysdata = hose;
+ fake_bus.ops = hose->pci_ops;
+
+ if (bus != top_bus)
+ /* Fake a parent bus structure. */
+ fake_bus.parent = &fake_bus;
+ else
+ fake_bus.parent = NULL;
+
+ return pci_read_config_word(&fake_dev, offset, value);
+}
+
+int __init txx9_pci66_check(struct pci_controller *hose, int top_bus,
+ int current_bus)
+{
+ u32 pci_devfn;
+ unsigned short vid;
+ int cap66 = -1;
+ u16 stat;
+
+ /* It seems SLC90E66 needs some time after PCI reset... */
+ mdelay(80);
+
+ printk(KERN_INFO "PCI: Checking 66MHz capabilities...\n");
+
+ for (pci_devfn = 0; pci_devfn < 0xff; pci_devfn++) {
+ if (PCI_FUNC(pci_devfn))
+ continue;
+ if (early_read_config_word(hose, top_bus, current_bus,
+ pci_devfn, PCI_VENDOR_ID, &vid) !=
+ PCIBIOS_SUCCESSFUL)
+ continue;
+ if (vid == 0xffff)
+ continue;
+
+ /* check 66MHz capability */
+ if (cap66 < 0)
+ cap66 = 1;
+ if (cap66) {
+ early_read_config_word(hose, top_bus, current_bus,
+ pci_devfn, PCI_STATUS, &stat);
+ if (!(stat & PCI_STATUS_66MHZ)) {
+ printk(KERN_DEBUG
+ "PCI: %02x:%02x not 66MHz capable.\n",
+ current_bus, pci_devfn);
+ cap66 = 0;
+ break;
+ }
+ }
+ }
+ return cap66 > 0;
+}
+
+static struct resource primary_pci_mem_res[2] = {
+ { .name = "PCI MEM" },
+ { .name = "PCI MMIO" },
+};
+static struct resource primary_pci_io_res = { .name = "PCI IO" };
+struct pci_controller txx9_primary_pcic = {
+ .mem_resource = &primary_pci_mem_res[0],
+ .io_resource = &primary_pci_io_res,
+};
+
+#ifdef CONFIG_64BIT
+int txx9_pci_mem_high __initdata = 1;
+#else
+int txx9_pci_mem_high __initdata;
+#endif
+
+/*
+ * allocate pci_controller and resources.
+ * mem_base, io_base: physical addresss. 0 for auto assignment.
+ * mem_size and io_size means max size on auto assignment.
+ * pcic must be &txx9_primary_pcic or NULL.
+ */
+struct pci_controller *__init
+txx9_alloc_pci_controller(struct pci_controller *pcic,
+ unsigned long mem_base, unsigned long mem_size,
+ unsigned long io_base, unsigned long io_size)
+{
+ struct pcic {
+ struct pci_controller c;
+ struct resource r_mem[2];
+ struct resource r_io;
+ } *new = NULL;
+ int min_size = 0x10000;
+
+ if (!pcic) {
+ new = kzalloc(sizeof(*new), GFP_KERNEL);
+ if (!new)
+ return NULL;
+ new->r_mem[0].name = "PCI mem";
+ new->r_mem[1].name = "PCI mmio";
+ new->r_io.name = "PCI io";
+ new->c.mem_resource = new->r_mem;
+ new->c.io_resource = &new->r_io;
+ pcic = &new->c;
+ } else
+ BUG_ON(pcic != &txx9_primary_pcic);
+ pcic->io_resource->flags = IORESOURCE_IO;
+
+ /*
+ * for auto assignment, first search a (big) region for PCI
+ * MEM, then search a region for PCI IO.
+ */
+ if (mem_base) {
+ pcic->mem_resource[0].start = mem_base;
+ pcic->mem_resource[0].end = mem_base + mem_size - 1;
+ if (request_resource(&iomem_resource, &pcic->mem_resource[0]))
+ goto free_and_exit;
+ } else {
+ unsigned long min = 0, max = 0x20000000; /* low 512MB */
+ if (!mem_size) {
+ /* default size for auto assignment */
+ if (txx9_pci_mem_high)
+ mem_size = 0x20000000; /* mem:512M(max) */
+ else
+ mem_size = 0x08000000; /* mem:128M(max) */
+ }
+ if (txx9_pci_mem_high) {
+ min = 0x20000000;
+ max = 0xe0000000;
+ }
+ /* search free region for PCI MEM */
+ for (; mem_size >= min_size; mem_size /= 2) {
+ if (allocate_resource(&iomem_resource,
+ &pcic->mem_resource[0],
+ mem_size, min, max,
+ mem_size, NULL, NULL) == 0)
+ break;
+ }
+ if (mem_size < min_size)
+ goto free_and_exit;
+ }
+
+ pcic->mem_resource[1].flags = IORESOURCE_MEM | IORESOURCE_BUSY;
+ if (io_base) {
+ pcic->mem_resource[1].start = io_base;
+ pcic->mem_resource[1].end = io_base + io_size - 1;
+ if (request_resource(&iomem_resource, &pcic->mem_resource[1]))
+ goto release_and_exit;
+ } else {
+ if (!io_size)
+ /* default size for auto assignment */
+ io_size = 0x01000000; /* io:16M(max) */
+ /* search free region for PCI IO in low 512MB */
+ for (; io_size >= min_size; io_size /= 2) {
+ if (allocate_resource(&iomem_resource,
+ &pcic->mem_resource[1],
+ io_size, 0, 0x20000000,
+ io_size, NULL, NULL) == 0)
+ break;
+ }
+ if (io_size < min_size)
+ goto release_and_exit;
+ io_base = pcic->mem_resource[1].start;
+ }
+
+ pcic->mem_resource[0].flags = IORESOURCE_MEM;
+ if (pcic == &txx9_primary_pcic &&
+ mips_io_port_base == (unsigned long)-1) {
+ /* map ioport 0 to PCI I/O space address 0 */
+ set_io_port_base(IO_BASE + pcic->mem_resource[1].start);
+ pcic->io_resource->start = 0;
+ pcic->io_offset = 0; /* busaddr == ioaddr */
+ pcic->io_map_base = IO_BASE + pcic->mem_resource[1].start;
+ } else {
+ /* physaddr to ioaddr */
+ pcic->io_resource->start =
+ io_base - (mips_io_port_base - IO_BASE);
+ pcic->io_offset = io_base - (mips_io_port_base - IO_BASE);
+ pcic->io_map_base = mips_io_port_base;
+ }
+ pcic->io_resource->end = pcic->io_resource->start + io_size - 1;
+
+ pcic->mem_offset = 0; /* busaddr == physaddr */
+
+ printk(KERN_INFO "PCI: IO 0x%08llx-0x%08llx MEM 0x%08llx-0x%08llx\n",
+ (unsigned long long)pcic->mem_resource[1].start,
+ (unsigned long long)pcic->mem_resource[1].end,
+ (unsigned long long)pcic->mem_resource[0].start,
+ (unsigned long long)pcic->mem_resource[0].end);
+
+ /* register_pci_controller() will request MEM resource */
+ release_resource(&pcic->mem_resource[0]);
+ return pcic;
+ release_and_exit:
+ release_resource(&pcic->mem_resource[0]);
+ free_and_exit:
+ kfree(new);
+ printk(KERN_ERR "PCI: Failed to allocate resources.\n");
+ return NULL;
+}
+
+static int __init
+txx9_arch_pci_init(void)
+{
+ PCIBIOS_MIN_IO = 0x8000; /* reseve legacy I/O space */
+ return 0;
+}
+arch_initcall(txx9_arch_pci_init);
+
+/* IRQ/IDSEL mapping */
+int txx9_pci_option =
+#ifdef CONFIG_PICMG_PCI_BACKPLANE_DEFAULT
+ TXX9_PCI_OPT_PICMG |
+#endif
+ TXX9_PCI_OPT_CLK_AUTO;
+
+enum txx9_pci_err_action txx9_pci_err_action = TXX9_PCI_ERR_REPORT;
+
+#ifdef CONFIG_TOSHIBA_FPCIB0
+static irqreturn_t i8259_interrupt(int irq, void *dev_id)
+{
+ int isairq;
+
+ isairq = i8259_irq();
+ if (unlikely(isairq <= I8259A_IRQ_BASE))
+ return IRQ_NONE;
+ generic_handle_irq(isairq);
+ return IRQ_HANDLED;
+}
+
+static int __init
+txx9_i8259_irq_setup(int irq)
+{
+ int err;
+
+ init_i8259_irqs();
+ err = request_irq(irq, &i8259_interrupt, IRQF_DISABLED|IRQF_SHARED,
+ "cascade(i8259)", (void *)(long)irq);
+ if (!err)
+ printk(KERN_INFO "PCI-ISA bridge PIC (irq %d)\n", irq);
+ return err;
+}
+
+static void __init quirk_slc90e66_bridge(struct pci_dev *dev)
+{
+ int irq; /* PCI/ISA Bridge interrupt */
+ u8 reg_64;
+ u32 reg_b0;
+ u8 reg_e1;
+ irq = pcibios_map_irq(dev, PCI_SLOT(dev->devfn), 1); /* INTA */
+ if (!irq)
+ return;
+ txx9_i8259_irq_setup(irq);
+ pci_read_config_byte(dev, 0x64, &reg_64);
+ pci_read_config_dword(dev, 0xb0, &reg_b0);
+ pci_read_config_byte(dev, 0xe1, &reg_e1);
+ /* serial irq control */
+ reg_64 = 0xd0;
+ /* serial irq pin */
+ reg_b0 |= 0x00010000;
+ /* ide irq on isa14 */
+ reg_e1 &= 0xf0;
+ reg_e1 |= 0x0d;
+ pci_write_config_byte(dev, 0x64, reg_64);
+ pci_write_config_dword(dev, 0xb0, reg_b0);
+ pci_write_config_byte(dev, 0xe1, reg_e1);
+
+ smsc_fdc37m81x_init(0x3f0);
+ smsc_fdc37m81x_config_beg();
+ smsc_fdc37m81x_config_set(SMSC_FDC37M81X_DNUM,
+ SMSC_FDC37M81X_KBD);
+ smsc_fdc37m81x_config_set(SMSC_FDC37M81X_INT, 1);
+ smsc_fdc37m81x_config_set(SMSC_FDC37M81X_INT2, 12);
+ smsc_fdc37m81x_config_set(SMSC_FDC37M81X_ACTIVE,
+ 1);
+ smsc_fdc37m81x_config_end();
+}
+
+static void quirk_slc90e66_ide(struct pci_dev *dev)
+{
+ unsigned char dat;
+ int regs[2] = {0x41, 0x43};
+ int i;
+
+ /* SMSC SLC90E66 IDE uses irq 14, 15 (default) */
+ pci_write_config_byte(dev, PCI_INTERRUPT_LINE, 14);
+ pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &dat);
+ printk(KERN_INFO "PCI: %s: IRQ %02x", pci_name(dev), dat);
+ /* enable SMSC SLC90E66 IDE */
+ for (i = 0; i < ARRAY_SIZE(regs); i++) {
+ pci_read_config_byte(dev, regs[i], &dat);
+ pci_write_config_byte(dev, regs[i], dat | 0x80);
+ pci_read_config_byte(dev, regs[i], &dat);
+ printk(KERN_CONT " IDETIM%d %02x", i, dat);
+ }
+ pci_read_config_byte(dev, 0x5c, &dat);
+ /*
+ * !!! DO NOT REMOVE THIS COMMENT IT IS REQUIRED BY SMSC !!!
+ *
+ * This line of code is intended to provide the user with a work
+ * around solution to the anomalies cited in SMSC's anomaly sheet
+ * entitled, "SLC90E66 Functional Rev.J_0.1 Anomalies"".
+ *
+ * !!! DO NOT REMOVE THIS COMMENT IT IS REQUIRED BY SMSC !!!
+ */
+ dat |= 0x01;
+ pci_write_config_byte(dev, regs[i], dat);
+ pci_read_config_byte(dev, 0x5c, &dat);
+ printk(KERN_CONT " REG5C %02x", dat);
+ printk(KERN_CONT "\n");
+}
+#endif /* CONFIG_TOSHIBA_FPCIB0 */
+
+static void final_fixup(struct pci_dev *dev)
+{
+ unsigned char bist;
+
+ /* Do build-in self test */
+ if (pci_read_config_byte(dev, PCI_BIST, &bist) == PCIBIOS_SUCCESSFUL &&
+ (bist & PCI_BIST_CAPABLE)) {
+ unsigned long timeout;
+ pci_set_power_state(dev, PCI_D0);
+ printk(KERN_INFO "PCI: %s BIST...", pci_name(dev));
+ pci_write_config_byte(dev, PCI_BIST, PCI_BIST_START);
+ timeout = jiffies + HZ * 2; /* timeout after 2 sec */
+ do {
+ pci_read_config_byte(dev, PCI_BIST, &bist);
+ if (time_after(jiffies, timeout))
+ break;
+ } while (bist & PCI_BIST_START);
+ if (bist & (PCI_BIST_CODE_MASK | PCI_BIST_START))
+ printk(KERN_CONT "failed. (0x%x)\n", bist);
+ else
+ printk(KERN_CONT "OK.\n");
+ }
+}
+
+#ifdef CONFIG_TOSHIBA_FPCIB0
+#define PCI_DEVICE_ID_EFAR_SLC90E66_0 0x9460
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_EFAR, PCI_DEVICE_ID_EFAR_SLC90E66_0,
+ quirk_slc90e66_bridge);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_EFAR, PCI_DEVICE_ID_EFAR_SLC90E66_1,
+ quirk_slc90e66_ide);
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_EFAR, PCI_DEVICE_ID_EFAR_SLC90E66_1,
+ quirk_slc90e66_ide);
+#endif
+DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, final_fixup);
+DECLARE_PCI_FIXUP_RESUME(PCI_ANY_ID, PCI_ANY_ID, final_fixup);
+
+int pcibios_plat_dev_init(struct pci_dev *dev)
+{
+ return 0;
+}
+
+int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
+{
+ return txx9_board_vec->pci_map_irq(dev, slot, pin);
+}
diff --git a/arch/mips/txx9/generic/setup.c b/arch/mips/txx9/generic/setup.c
new file mode 100644
index 0000000..5afc5d5
--- /dev/null
+++ b/arch/mips/txx9/generic/setup.c
@@ -0,0 +1,212 @@
+/*
+ * linux/arch/mips/txx9/generic/setup.c
+ *
+ * Based on linux/arch/mips/txx9/rbtx4938/setup.c,
+ * and RBTX49xx patch from CELF patch archive.
+ *
+ * 2003-2005 (c) MontaVista Software, Inc.
+ * (C) Copyright TOSHIBA CORPORATION 2000-2001, 2004-2007
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/string.h>
+#include <linux/module.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <asm/bootinfo.h>
+#include <asm/txx9/generic.h>
+#ifdef CONFIG_CPU_TX49XX
+#include <asm/txx9/tx4938.h>
+#endif
+
+/* EBUSC settings of TX4927, etc. */
+struct resource txx9_ce_res[8];
+static char txx9_ce_res_name[8][4]; /* "CEn" */
+
+/* pcode, internal register */
+char txx9_pcode_str[8];
+static struct resource txx9_reg_res = {
+ .name = txx9_pcode_str,
+ .flags = IORESOURCE_MEM,
+};
+void __init
+txx9_reg_res_init(unsigned int pcode, unsigned long base, unsigned long size)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(txx9_ce_res); i++) {
+ sprintf(txx9_ce_res_name[i], "CE%d", i);
+ txx9_ce_res[i].flags = IORESOURCE_MEM;
+ txx9_ce_res[i].name = txx9_ce_res_name[i];
+ }
+
+ sprintf(txx9_pcode_str, "TX%x", pcode);
+ if (base) {
+ txx9_reg_res.start = base & 0xfffffffffULL;
+ txx9_reg_res.end = (base & 0xfffffffffULL) + (size - 1);
+ request_resource(&iomem_resource, &txx9_reg_res);
+ }
+}
+
+/* clocks */
+unsigned int txx9_master_clock;
+unsigned int txx9_cpu_clock;
+unsigned int txx9_gbus_clock;
+
+
+/* Minimum CLK support */
+
+struct clk *clk_get(struct device *dev, const char *id)
+{
+ if (!strcmp(id, "spi-baseclk"))
+ return (struct clk *)(txx9_gbus_clock / 2 / 4);
+ if (!strcmp(id, "imbus_clk"))
+ return (struct clk *)(txx9_gbus_clock / 2);
+ return ERR_PTR(-ENOENT);
+}
+EXPORT_SYMBOL(clk_get);
+
+int clk_enable(struct clk *clk)
+{
+ return 0;
+}
+EXPORT_SYMBOL(clk_enable);
+
+void clk_disable(struct clk *clk)
+{
+}
+EXPORT_SYMBOL(clk_disable);
+
+unsigned long clk_get_rate(struct clk *clk)
+{
+ return (unsigned long)clk;
+}
+EXPORT_SYMBOL(clk_get_rate);
+
+void clk_put(struct clk *clk)
+{
+}
+EXPORT_SYMBOL(clk_put);
+
+extern struct txx9_board_vec jmr3927_vec;
+extern struct txx9_board_vec rbtx4927_vec;
+extern struct txx9_board_vec rbtx4937_vec;
+extern struct txx9_board_vec rbtx4938_vec;
+
+struct txx9_board_vec *txx9_board_vec __initdata;
+static char txx9_system_type[32];
+
+void __init prom_init_cmdline(void)
+{
+ int argc = (int)fw_arg0;
+ char **argv = (char **)fw_arg1;
+ int i; /* Always ignore the "-c" at argv[0] */
+
+ /* ignore all built-in args if any f/w args given */
+ if (argc > 1)
+ *arcs_cmdline = '\0';
+
+ for (i = 1; i < argc; i++) {
+ if (i != 1)
+ strcat(arcs_cmdline, " ");
+ strcat(arcs_cmdline, argv[i]);
+ }
+}
+
+void __init prom_init(void)
+{
+#ifdef CONFIG_CPU_TX39XX
+ txx9_board_vec = &jmr3927_vec;
+#endif
+#ifdef CONFIG_CPU_TX49XX
+ switch (TX4938_REV_PCODE()) {
+ case 0x4927:
+ txx9_board_vec = &rbtx4927_vec;
+ break;
+ case 0x4937:
+ txx9_board_vec = &rbtx4937_vec;
+ break;
+ case 0x4938:
+ txx9_board_vec = &rbtx4938_vec;
+ break;
+ }
+#endif
+
+ strcpy(txx9_system_type, txx9_board_vec->system);
+
+ txx9_board_vec->prom_init();
+}
+
+void __init prom_free_prom_memory(void)
+{
+}
+
+const char *get_system_type(void)
+{
+ return txx9_system_type;
+}
+
+char * __init prom_getcmdline(void)
+{
+ return &(arcs_cmdline[0]);
+}
+
+/* wrappers */
+void __init plat_mem_setup(void)
+{
+ txx9_board_vec->mem_setup();
+}
+
+void __init arch_init_irq(void)
+{
+ txx9_board_vec->irq_setup();
+}
+
+void __init plat_time_init(void)
+{
+ txx9_board_vec->time_init();
+}
+
+static int __init _txx9_arch_init(void)
+{
+ if (txx9_board_vec->arch_init)
+ txx9_board_vec->arch_init();
+ return 0;
+}
+arch_initcall(_txx9_arch_init);
+
+static int __init _txx9_device_init(void)
+{
+ if (txx9_board_vec->device_init)
+ txx9_board_vec->device_init();
+ return 0;
+}
+device_initcall(_txx9_device_init);
+
+int (*txx9_irq_dispatch)(int pending);
+asmlinkage void plat_irq_dispatch(void)
+{
+ int pending = read_c0_status() & read_c0_cause() & ST0_IM;
+ int irq = txx9_irq_dispatch(pending);
+
+ if (likely(irq >= 0))
+ do_IRQ(irq);
+ else
+ spurious_interrupt();
+}
+
+/* see include/asm-mips/mach-tx39xx/mangle-port.h, for example. */
+#ifdef NEEDS_TXX9_SWIZZLE_ADDR_B
+static unsigned long __swizzle_addr_none(unsigned long port)
+{
+ return port;
+}
+unsigned long (*__swizzle_addr_b)(unsigned long port) = __swizzle_addr_none;
+EXPORT_SYMBOL(__swizzle_addr_b);
+#endif
diff --git a/arch/mips/txx9/generic/smsc_fdc37m81x.c b/arch/mips/txx9/generic/smsc_fdc37m81x.c
new file mode 100644
index 0000000..69e4874
--- /dev/null
+++ b/arch/mips/txx9/generic/smsc_fdc37m81x.c
@@ -0,0 +1,172 @@
+/*
+ * Interface for smsc fdc48m81x Super IO chip
+ *
+ * Author: MontaVista Software, Inc. source@mvista.com
+ *
+ * 2001-2003 (c) MontaVista Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ *
+ * Copyright 2004 (c) MontaVista Software, Inc.
+ */
+#include <linux/init.h>
+#include <linux/types.h>
+#include <asm/io.h>
+#include <asm/txx9/smsc_fdc37m81x.h>
+
+#define DEBUG
+
+/* Common Registers */
+#define SMSC_FDC37M81X_CONFIG_INDEX 0x00
+#define SMSC_FDC37M81X_CONFIG_DATA 0x01
+#define SMSC_FDC37M81X_CONF 0x02
+#define SMSC_FDC37M81X_INDEX 0x03
+#define SMSC_FDC37M81X_DNUM 0x07
+#define SMSC_FDC37M81X_DID 0x20
+#define SMSC_FDC37M81X_DREV 0x21
+#define SMSC_FDC37M81X_PCNT 0x22
+#define SMSC_FDC37M81X_PMGT 0x23
+#define SMSC_FDC37M81X_OSC 0x24
+#define SMSC_FDC37M81X_CONFPA0 0x26
+#define SMSC_FDC37M81X_CONFPA1 0x27
+#define SMSC_FDC37M81X_TEST4 0x2B
+#define SMSC_FDC37M81X_TEST5 0x2C
+#define SMSC_FDC37M81X_TEST1 0x2D
+#define SMSC_FDC37M81X_TEST2 0x2E
+#define SMSC_FDC37M81X_TEST3 0x2F
+
+/* Logical device numbers */
+#define SMSC_FDC37M81X_FDD 0x00
+#define SMSC_FDC37M81X_SERIAL1 0x04
+#define SMSC_FDC37M81X_SERIAL2 0x05
+#define SMSC_FDC37M81X_KBD 0x07
+
+/* Logical device Config Registers */
+#define SMSC_FDC37M81X_ACTIVE 0x30
+#define SMSC_FDC37M81X_BASEADDR0 0x60
+#define SMSC_FDC37M81X_BASEADDR1 0x61
+#define SMSC_FDC37M81X_INT 0x70
+#define SMSC_FDC37M81X_INT2 0x72
+#define SMSC_FDC37M81X_MODE 0xF0
+
+/* Chip Config Values */
+#define SMSC_FDC37M81X_CONFIG_ENTER 0x55
+#define SMSC_FDC37M81X_CONFIG_EXIT 0xaa
+#define SMSC_FDC37M81X_CHIP_ID 0x4d
+
+static unsigned long g_smsc_fdc37m81x_base = 0;
+
+static inline unsigned char smsc_fdc37m81x_rd(unsigned char index)
+{
+ outb(index, g_smsc_fdc37m81x_base + SMSC_FDC37M81X_CONFIG_INDEX);
+
+ return inb(g_smsc_fdc37m81x_base + SMSC_FDC37M81X_CONFIG_DATA);
+}
+
+static inline void smsc_dc37m81x_wr(unsigned char index, unsigned char data)
+{
+ outb(index, g_smsc_fdc37m81x_base + SMSC_FDC37M81X_CONFIG_INDEX);
+ outb(data, g_smsc_fdc37m81x_base + SMSC_FDC37M81X_CONFIG_DATA);
+}
+
+void smsc_fdc37m81x_config_beg(void)
+{
+ if (g_smsc_fdc37m81x_base) {
+ outb(SMSC_FDC37M81X_CONFIG_ENTER,
+ g_smsc_fdc37m81x_base + SMSC_FDC37M81X_CONFIG_INDEX);
+ }
+}
+
+void smsc_fdc37m81x_config_end(void)
+{
+ if (g_smsc_fdc37m81x_base)
+ outb(SMSC_FDC37M81X_CONFIG_EXIT,
+ g_smsc_fdc37m81x_base + SMSC_FDC37M81X_CONFIG_INDEX);
+}
+
+u8 smsc_fdc37m81x_config_get(u8 reg)
+{
+ u8 val = 0;
+
+ if (g_smsc_fdc37m81x_base)
+ val = smsc_fdc37m81x_rd(reg);
+
+ return val;
+}
+
+void smsc_fdc37m81x_config_set(u8 reg, u8 val)
+{
+ if (g_smsc_fdc37m81x_base)
+ smsc_dc37m81x_wr(reg, val);
+}
+
+unsigned long __init smsc_fdc37m81x_init(unsigned long port)
+{
+ const int field = sizeof(unsigned long) * 2;
+ u8 chip_id;
+
+ if (g_smsc_fdc37m81x_base)
+ printk("smsc_fdc37m81x_init() stepping on old base=0x%0*lx\n",
+ field, g_smsc_fdc37m81x_base);
+
+ g_smsc_fdc37m81x_base = port;
+
+ smsc_fdc37m81x_config_beg();
+
+ chip_id = smsc_fdc37m81x_rd(SMSC_FDC37M81X_DID);
+ if (chip_id == SMSC_FDC37M81X_CHIP_ID)
+ smsc_fdc37m81x_config_end();
+ else {
+ printk("smsc_fdc37m81x_init() unknow chip id 0x%02x\n",
+ chip_id);
+ g_smsc_fdc37m81x_base = 0;
+ }
+
+ return g_smsc_fdc37m81x_base;
+}
+
+#ifdef DEBUG
+void smsc_fdc37m81x_config_dump_one(char *key, u8 dev, u8 reg)
+{
+ printk("%s: dev=0x%02x reg=0x%02x val=0x%02x\n", key, dev, reg,
+ smsc_fdc37m81x_rd(reg));
+}
+
+void smsc_fdc37m81x_config_dump(void)
+{
+ u8 orig;
+ char *fname = "smsc_fdc37m81x_config_dump()";
+
+ smsc_fdc37m81x_config_beg();
+
+ orig = smsc_fdc37m81x_rd(SMSC_FDC37M81X_DNUM);
+
+ printk("%s: common\n", fname);
+ smsc_fdc37m81x_config_dump_one(fname, SMSC_FDC37M81X_NONE,
+ SMSC_FDC37M81X_DNUM);
+ smsc_fdc37m81x_config_dump_one(fname, SMSC_FDC37M81X_NONE,
+ SMSC_FDC37M81X_DID);
+ smsc_fdc37m81x_config_dump_one(fname, SMSC_FDC37M81X_NONE,
+ SMSC_FDC37M81X_DREV);
+ smsc_fdc37m81x_config_dump_one(fname, SMSC_FDC37M81X_NONE,
+ SMSC_FDC37M81X_PCNT);
+ smsc_fdc37m81x_config_dump_one(fname, SMSC_FDC37M81X_NONE,
+ SMSC_FDC37M81X_PMGT);
+
+ printk("%s: keyboard\n", fname);
+ smsc_dc37m81x_wr(SMSC_FDC37M81X_DNUM, SMSC_FDC37M81X_KBD);
+ smsc_fdc37m81x_config_dump_one(fname, SMSC_FDC37M81X_KBD,
+ SMSC_FDC37M81X_ACTIVE);
+ smsc_fdc37m81x_config_dump_one(fname, SMSC_FDC37M81X_KBD,
+ SMSC_FDC37M81X_INT);
+ smsc_fdc37m81x_config_dump_one(fname, SMSC_FDC37M81X_KBD,
+ SMSC_FDC37M81X_INT2);
+ smsc_fdc37m81x_config_dump_one(fname, SMSC_FDC37M81X_KBD,
+ SMSC_FDC37M81X_LDCR_F0);
+
+ smsc_dc37m81x_wr(SMSC_FDC37M81X_DNUM, orig);
+
+ smsc_fdc37m81x_config_end();
+}
+#endif
OpenPOWER on IntegriCloud