diff options
author | Ingo Molnar <mingo@elte.hu> | 2008-07-30 19:36:55 +0200 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-07-30 19:36:55 +0200 |
commit | bc588df79ebfb710abc27342fccf336a68ed1216 (patch) | |
tree | e50e125eaa6da83fa715704e53c1bde013d1ef8e /arch/mips/txx9 | |
parent | bce7f793daec3e65ec5c5705d2457b81fe7b5725 (diff) | |
parent | 15dd859cacf312f606f54502d1f66537a1e5c78c (diff) |
Merge branch 'x86/core' into x86/xsave
Diffstat (limited to 'arch/mips/txx9')
25 files changed, 3657 insertions, 0 deletions
diff --git a/arch/mips/txx9/Kconfig b/arch/mips/txx9/Kconfig new file mode 100644 index 00000000000..6de4c5aa92b --- /dev/null +++ b/arch/mips/txx9/Kconfig @@ -0,0 +1,117 @@ +config TOSHIBA_JMR3927 + bool "Toshiba JMR-TX3927 board" + depends on MACH_TX39XX + select SOC_TX3927 + +config TOSHIBA_RBTX4927 + bool "Toshiba RBTX49[23]7 board" + depends on MACH_TX49XX + select SOC_TX4927 + # TX4937 is subset of TX4938 + select SOC_TX4938 + help + This Toshiba board is based on the TX4927 processor. Say Y here to + support this machine type + +config TOSHIBA_RBTX4938 + bool "Toshiba RBTX4938 board" + depends on MACH_TX49XX + select SOC_TX4938 + help + This Toshiba board is based on the TX4938 processor. Say Y here to + support this machine type + +config SOC_TX3927 + bool + select CEVT_TXX9 + select DMA_NONCOHERENT + select HAS_TXX9_SERIAL + select HW_HAS_PCI + select IRQ_TXX9 + select SWAP_IO_SPACE + select SYS_HAS_CPU_TX39XX + select SYS_SUPPORTS_32BIT_KERNEL + select SYS_SUPPORTS_LITTLE_ENDIAN + select SYS_SUPPORTS_BIG_ENDIAN + select GENERIC_HARDIRQS_NO__DO_IRQ + select GPIO_TXX9 + +config SOC_TX4927 + bool + select CEVT_R4K + select CSRC_R4K + select CEVT_TXX9 + select DMA_NONCOHERENT + select HAS_TXX9_SERIAL + select HW_HAS_PCI + select IRQ_CPU + select IRQ_TXX9 + select PCI_TX4927 + select SWAP_IO_SPACE + select SYS_HAS_CPU_TX49XX + select SYS_SUPPORTS_32BIT_KERNEL + select SYS_SUPPORTS_64BIT_KERNEL + select SYS_SUPPORTS_LITTLE_ENDIAN + select SYS_SUPPORTS_BIG_ENDIAN + select SYS_SUPPORTS_KGDB + select GENERIC_HARDIRQS_NO__DO_IRQ + select GPIO_TXX9 + +config SOC_TX4938 + bool + select CEVT_R4K + select CSRC_R4K + select CEVT_TXX9 + select DMA_NONCOHERENT + select HAS_TXX9_SERIAL + select HW_HAS_PCI + select IRQ_CPU + select IRQ_TXX9 + select PCI_TX4927 + select SWAP_IO_SPACE + select SYS_HAS_CPU_TX49XX + select SYS_SUPPORTS_32BIT_KERNEL + select SYS_SUPPORTS_64BIT_KERNEL + select SYS_SUPPORTS_LITTLE_ENDIAN + select SYS_SUPPORTS_BIG_ENDIAN + select SYS_SUPPORTS_KGDB + select GENERIC_HARDIRQS_NO__DO_IRQ + select GPIO_TXX9 + +config TOSHIBA_FPCIB0 + bool "FPCIB0 Backplane Support" + depends on PCI && (MACH_TX39XX || MACH_TX49XX) + select I8259 + +config PICMG_PCI_BACKPLANE_DEFAULT + bool "Support for PICMG PCI Backplane" + depends on PCI && (MACH_TX39XX || MACH_TX49XX) + default y if !TOSHIBA_FPCIB0 + +if TOSHIBA_RBTX4938 + +comment "Multiplex Pin Select" +choice + prompt "PIO[58:61]" + default TOSHIBA_RBTX4938_MPLEX_PIO58_61 + +config TOSHIBA_RBTX4938_MPLEX_PIO58_61 + bool "PIO" +config TOSHIBA_RBTX4938_MPLEX_NAND + bool "NAND" +config TOSHIBA_RBTX4938_MPLEX_ATA + bool "ATA" + +endchoice + +config TX4938_NAND_BOOT + depends on EXPERIMENTAL && TOSHIBA_RBTX4938_MPLEX_NAND + bool "NAND Boot Support (EXPERIMENTAL)" + help + This is only for Toshiba RBTX4938 reference board, which has NAND IPL. + Select this option if you need to use NAND boot. + +endif + +config PCI_TX4927 + bool diff --git a/arch/mips/txx9/generic/Makefile b/arch/mips/txx9/generic/Makefile new file mode 100644 index 00000000000..9c120771e65 --- /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 setup_tx4927.o irq_tx4927.o +obj-$(CONFIG_SOC_TX4938) += mem_tx4927.o setup_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 00000000000..33b9c672a32 --- /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 00000000000..cbea1fdde82 --- /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 & 0xfffffffffULL); + 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 00000000000..6eac684bf19 --- /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 & 0xfffffffffULL); + 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 00000000000..ef6ea6e9787 --- /dev/null +++ b/arch/mips/txx9/generic/mem_tx4927.c @@ -0,0 +1,77 @@ +/* + * linux/arch/mips/txx9/generic/mem_tx4927.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> +#include <asm/txx9/tx4927.h> + +static unsigned int __init tx4927_process_sdccr(u64 __iomem *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; + + val = __raw_readq(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 & (7 << 2)) >> 2); + sdccr_mw = ((val & (1 << 0)) >> 0); + + if (sdccr_ce) { + bs = 2 << sdccr_bs; + rs = 2048 << sdccr_rs; + cs = 256 << sdccr_cs; + mw = 8 >> sdccr_mw; + } + + return rs * cs * mw * bs; +} + +unsigned int __init tx4927_get_mem_size(void) +{ + unsigned int total = 0; + int i; + + for (i = 0; i < ARRAY_SIZE(tx4927_sdramcptr->cr); i++) + total += tx4927_process_sdccr(&tx4927_sdramcptr->cr[i]); + return total; +} diff --git a/arch/mips/txx9/generic/pci.c b/arch/mips/txx9/generic/pci.c new file mode 100644 index 00000000000..0b92d8c1320 --- /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, ®_64); + pci_read_config_dword(dev, 0xb0, ®_b0); + pci_read_config_byte(dev, 0xe1, ®_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 00000000000..8c60c78b9a9 --- /dev/null +++ b/arch/mips/txx9/generic/setup.c @@ -0,0 +1,246 @@ +/* + * 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 <linux/gpio.h> +#include <asm/bootinfo.h> +#include <asm/time.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 */ +unsigned int txx9_pcode; +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; + +int txx9_ccfg_toeon __initdata = 1; + +/* Minimum CLK support */ + +struct clk *clk_get(struct device *dev, const char *id) +{ + if (!strcmp(id, "spi-baseclk")) + return (struct clk *)((unsigned long)txx9_gbus_clock / 2 / 4); + if (!strcmp(id, "imbus_clk")) + return (struct clk *)((unsigned long)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); + +/* GPIO support */ + +#ifdef CONFIG_GENERIC_GPIO +int gpio_to_irq(unsigned gpio) +{ + return -EINVAL; +} +EXPORT_SYMBOL(gpio_to_irq); + +int irq_to_gpio(unsigned irq) +{ + return -EINVAL; +} +EXPORT_SYMBOL(irq_to_gpio); +#endif + +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] */ +#ifdef CONFIG_64BIT + char *fixed_argv[32]; + for (i = 0; i < argc; i++) + fixed_argv[i] = (char *)(long)(*((__s32 *)argv + i)); + argv = fixed_argv; +#endif + + /* 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()) { +#ifdef CONFIG_TOSHIBA_RBTX4927 + case 0x4927: + txx9_board_vec = &rbtx4927_vec; + break; + case 0x4937: + txx9_board_vec = &rbtx4937_vec; + break; +#endif +#ifdef CONFIG_TOSHIBA_RBTX4938 + case 0x4938: + txx9_board_vec = &rbtx4938_vec; + break; +#endif + } +#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) +{ + ioport_resource.start = 0; + ioport_resource.end = ~0UL; /* no limit */ + iomem_resource.start = 0; + iomem_resource.end = ~0UL; /* no limit */ + 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/setup_tx4927.c b/arch/mips/txx9/generic/setup_tx4927.c new file mode 100644 index 00000000000..89d6e28add9 --- /dev/null +++ b/arch/mips/txx9/generic/setup_tx4927.c @@ -0,0 +1,194 @@ +/* + * TX4927 setup routines + * 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/ioport.h> +#include <linux/delay.h> +#include <linux/serial_core.h> +#include <linux/param.h> +#include <asm/txx9irq.h> +#include <asm/txx9tmr.h> +#include <asm/txx9pio.h> +#include <asm/txx9/generic.h> +#include <asm/txx9/tx4927.h> + +void __init tx4927_wdr_init(void) +{ + /* clear WatchDogReset (W1C) */ + tx4927_ccfg_set(TX4927_CCFG_WDRST); + /* do reset on watchdog */ + tx4927_ccfg_set(TX4927_CCFG_WR); +} + +static struct resource tx4927_sdram_resource[4]; + +void __init tx4927_setup(void) +{ + int i; + __u32 divmode; + int cpuclk = 0; + u64 ccfg; + + txx9_reg_res_init(TX4927_REV_PCODE(), TX4927_REG_BASE, + TX4927_REG_SIZE); + + /* SDRAMC,EBUSC are configured by PROM */ + for (i = 0; i < 8; i++) { + if (!(TX4927_EBUSC_CR(i) & 0x8)) + continue; /* disabled */ + txx9_ce_res[i].start = (unsigned long)TX4927_EBUSC_BA(i); + txx9_ce_res[i].end = + txx9_ce_res[i].start + TX4927_EBUSC_SIZE(i) - 1; + request_resource(&iomem_resource, &txx9_ce_res[i]); + } + + /* clocks */ + ccfg = ____raw_readq(&tx4927_ccfgptr->ccfg); + if (txx9_master_clock) { + /* calculate gbus_clock and cpu_clock from master_clock */ + divmode = (__u32)ccfg & TX4927_CCFG_DIVMODE_MASK; + switch (divmode) { + case TX4927_CCFG_DIVMODE_8: + case TX4927_CCFG_DIVMODE_10: + case TX4927_CCFG_DIVMODE_12: + case TX4927_CCFG_DIVMODE_16: + txx9_gbus_clock = txx9_master_clock * 4; break; + default: + txx9_gbus_clock = txx9_master_clock; + } + switch (divmode) { + case TX4927_CCFG_DIVMODE_2: + case TX4927_CCFG_DIVMODE_8: + cpuclk = txx9_gbus_clock * 2; break; + case TX4927_CCFG_DIVMODE_2_5: + case TX4927_CCFG_DIVMODE_10: + cpuclk = txx9_gbus_clock * 5 / 2; break; + case TX4927_CCFG_DIVMODE_3: + case TX4927_CCFG_DIVMODE_12: + cpuclk = txx9_gbus_clock * 3; break; + case TX4927_CCFG_DIVMODE_4: + case TX4927_CCFG_DIVMODE_16: + cpuclk = txx9_gbus_clock * 4; break; + } + txx9_cpu_clock = cpuclk; + } else { + if (txx9_cpu_clock == 0) + txx9_cpu_clock = 200000000; /* 200MHz */ + /* calculate gbus_clock and master_clock from cpu_clock */ + cpuclk = txx9_cpu_clock; + divmode = (__u32)ccfg & TX4927_CCFG_DIVMODE_MASK; + switch (divmode) { + case TX4927_CCFG_DIVMODE_2: + case TX4927_CCFG_DIVMODE_8: + txx9_gbus_clock = cpuclk / 2; break; + case TX4927_CCFG_DIVMODE_2_5: + case TX4927_CCFG_DIVMODE_10: + txx9_gbus_clock = cpuclk * 2 / 5; break; + case TX4927_CCFG_DIVMODE_3: + case TX4927_CCFG_DIVMODE_12: + txx9_gbus_clock = cpuclk / 3; break; + case TX4927_CCFG_DIVMODE_4: + case TX4927_CCFG_DIVMODE_16: + txx9_gbus_clock = cpuclk / 4; break; + } + switch (divmode) { + case TX4927_CCFG_DIVMODE_8: + case TX4927_CCFG_DIVMODE_10: + case TX4927_CCFG_DIVMODE_12: + case TX4927_CCFG_DIVMODE_16: + txx9_master_clock = txx9_gbus_clock / 4; break; + default: + txx9_master_clock = txx9_gbus_clock; + } + } + /* change default value to udelay/mdelay take reasonable time */ + loops_per_jiffy = txx9_cpu_clock / HZ / 2; + + /* CCFG */ + tx4927_wdr_init(); + /* clear BusErrorOnWrite flag (W1C) */ + tx4927_ccfg_set(TX4927_CCFG_BEOW); + /* enable Timeout BusError */ + if (txx9_ccfg_toeon) + tx4927_ccfg_set(TX4927_CCFG_TOE); + + /* DMA selection */ + txx9_clear64(&tx4927_ccfgptr->pcfg, TX4927_PCFG_DMASEL_ALL); + + /* Use external clock for external arbiter */ + if (!(____raw_readq(&tx4927_ccfgptr->ccfg) & TX4927_CCFG_PCIARB)) + txx9_clear64(&tx4927_ccfgptr->pcfg, TX4927_PCFG_PCICLKEN_ALL); + + printk(KERN_INFO "%s -- %dMHz(M%dMHz) CRIR:%08x CCFG:%llx PCFG:%llx\n", + txx9_pcode_str, + (cpuclk + 500000) / 1000000, + (txx9_master_clock + 500000) / 1000000, + (__u32)____raw_readq(&tx4927_ccfgptr->crir), + (unsigned long long)____raw_readq(&tx4927_ccfgptr->ccfg), + (unsigned long long)____raw_readq(&tx4927_ccfgptr->pcfg)); + + printk(KERN_INFO "%s SDRAMC --", txx9_pcode_str); + for (i = 0; i < 4; i++) { + __u64 cr = TX4927_SDRAMC_CR(i); + unsigned long base, size; + if (!((__u32)cr & 0x00000400)) + continue; /* disabled */ + base = (unsigned long)(cr >> 49) << 21; + size = (((unsigned long)(cr >> 33) & 0x7fff) + 1) << 21; + printk(" CR%d:%016llx", i, (unsigned long long)cr); + tx4927_sdram_resource[i].name = "SDRAM"; + tx4927_sdram_resource[i].start = base; + tx4927_sdram_resource[i].end = base + size - 1; + tx4927_sdram_resource[i].flags = IORESOURCE_MEM; + request_resource(&iomem_resource, &tx4927_sdram_resource[i]); + } + printk(" TR:%09llx\n", + (unsigned long long)____raw_readq(&tx4927_sdramcptr->tr)); + + /* TMR */ + /* disable all timers */ + for (i = 0; i < TX4927_NR_TMR; i++) + txx9_tmr_init(TX4927_TMR_REG(i) & 0xfffffffffULL); + + /* PIO */ + txx9_gpio_init(TX4927_PIO_REG & 0xfffffffffULL, 0, TX4927_NUM_PIO); + __raw_writel(0, &tx4927_pioptr->maskcpu); + __raw_writel(0, &tx4927_pioptr->maskext); +} + +void __init tx4927_time_init(unsigned int tmrnr) +{ + if (____raw_readq(&tx4927_ccfgptr->ccfg) & TX4927_CCFG_TINTDIS) + txx9_clockevent_init(TX4927_TMR_REG(tmrnr) & 0xfffffffffULL, + TXX9_IRQ_BASE + TX4927_IR_TMR(tmrnr), + TXX9_IMCLK); +} + +void __init tx4927_setup_serial(void) +{ +#ifdef CONFIG_SERIAL_TXX9 + int i; + struct uart_port req; + + for (i = 0; i < 2; i++) { + memset(&req, 0, sizeof(req)); + req.line = i; + req.iotype = UPIO_MEM; + req.membase = (unsigned char __iomem *)TX4927_SIO_REG(i); + req.mapbase = TX4927_SIO_REG(i) & 0xfffffffffULL; + req.irq = TXX9_IRQ_BASE + TX4927_IR_SIO(i); + req.flags |= UPF_BUGGY_UART /*HAVE_CTS_LINE*/; + req.uartclk = TXX9_IMCLK; + early_serial_txx9_setup(&req); + } +#endif /* CONFIG_SERIAL_TXX9 */ +} diff --git a/arch/mips/txx9/generic/setup_tx4938.c b/arch/mips/txx9/generic/setup_tx4938.c new file mode 100644 index 00000000000..317378d8579 --- /dev/null +++ b/arch/mips/txx9/generic/setup_tx4938.c @@ -0,0 +1,259 @@ +/* + * TX4938/4937 setup routines + * 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/ioport.h> +#include <linux/delay.h> +#include <linux/serial_core.h> +#include <linux/param.h> +#include <asm/txx9irq.h> +#include <asm/txx9tmr.h> +#include <asm/txx9pio.h> +#include <asm/txx9/generic.h> +#include <asm/txx9/tx4938.h> + +void __init tx4938_wdr_init(void) +{ + /* clear WatchDogReset (W1C) */ + tx4938_ccfg_set(TX4938_CCFG_WDRST); + /* do reset on watchdog */ + tx4938_ccfg_set(TX4938_CCFG_WR); +} + +static struct resource tx4938_sdram_resource[4]; +static struct resource tx4938_sram_resource; + +#define TX4938_SRAM_SIZE 0x800 + +void __init tx4938_setup(void) +{ + int i; + __u32 divmode; + int cpuclk = 0; + u64 ccfg; + + txx9_reg_res_init(TX4938_REV_PCODE(), TX4938_REG_BASE, + TX4938_REG_SIZE); + + /* SDRAMC,EBUSC are configured by PROM */ + for (i = 0; i < 8; i++) { + if (!(TX4938_EBUSC_CR(i) & 0x8)) + continue; /* disabled */ + txx9_ce_res[i].start = (unsigned long)TX4938_EBUSC_BA(i); + txx9_ce_res[i].end = + txx9_ce_res[i].start + TX4938_EBUSC_SIZE(i) - 1; + request_resource(&iomem_resource, &txx9_ce_res[i]); + } + + /* clocks */ + ccfg = ____raw_readq(&tx4938_ccfgptr->ccfg); + if (txx9_master_clock) { + /* calculate gbus_clock and cpu_clock from master_clock */ + divmode = (__u32)ccfg & TX4938_CCFG_DIVMODE_MASK; + switch (divmode) { + case TX4938_CCFG_DIVMODE_8: + case TX4938_CCFG_DIVMODE_10: + case TX4938_CCFG_DIVMODE_12: + case TX4938_CCFG_DIVMODE_16: + case TX4938_CCFG_DIVMODE_18: + txx9_gbus_clock = txx9_master_clock * 4; break; + default: + txx9_gbus_clock = txx9_master_clock; + } + switch (divmode) { + case TX4938_CCFG_DIVMODE_2: + case TX4938_CCFG_DIVMODE_8: + cpuclk = txx9_gbus_clock * 2; break; + case TX4938_CCFG_DIVMODE_2_5: + case TX4938_CCFG_DIVMODE_10: + cpuclk = txx9_gbus_clock * 5 / 2; break; + case TX4938_CCFG_DIVMODE_3: + case TX4938_CCFG_DIVMODE_12: + cpuclk = txx9_gbus_clock * 3; break; + case TX4938_CCFG_DIVMODE_4: + case TX4938_CCFG_DIVMODE_16: + cpuclk = txx9_gbus_clock * 4; break; + case TX4938_CCFG_DIVMODE_4_5: + case TX4938_CCFG_DIVMODE_18: + cpuclk = txx9_gbus_clock * 9 / 2; break; + } + txx9_cpu_clock = cpuclk; + } else { + if (txx9_cpu_clock == 0) + txx9_cpu_clock = 300000000; /* 300MHz */ + /* calculate gbus_clock and master_clock from cpu_clock */ + cpuclk = txx9_cpu_clock; + divmode = (__u32)ccfg & TX4938_CCFG_DIVMODE_MASK; + switch (divmode) { + case TX4938_CCFG_DIVMODE_2: + case TX4938_CCFG_DIVMODE_8: + txx9_gbus_clock = cpuclk / 2; break; + case TX4938_CCFG_DIVMODE_2_5: + case TX4938_CCFG_DIVMODE_10: + txx9_gbus_clock = cpuclk * 2 / 5; break; + case TX4938_CCFG_DIVMODE_3: + case TX4938_CCFG_DIVMODE_12: + txx9_gbus_clock = cpuclk / 3; break; + case TX4938_CCFG_DIVMODE_4: + case TX4938_CCFG_DIVMODE_16: + txx9_gbus_clock = cpuclk / 4; break; + case TX4938_CCFG_DIVMODE_4_5: + case TX4938_CCFG_DIVMODE_18: + txx9_gbus_clock = cpuclk * 2 / 9; break; + } + switch (divmode) { + case TX4938_CCFG_DIVMODE_8: + case TX4938_CCFG_DIVMODE_10: + case TX4938_CCFG_DIVMODE_12: + case TX4938_CCFG_DIVMODE_16: + case TX4938_CCFG_DIVMODE_18: + txx9_master_clock = txx9_gbus_clock / 4; break; + default: + txx9_master_clock = txx9_gbus_clock; + } + } + /* change default value to udelay/mdelay take reasonable time */ + loops_per_jiffy = txx9_cpu_clock / HZ / 2; + + /* CCFG */ + tx4938_wdr_init(); + /* clear BusErrorOnWrite flag (W1C) */ + tx4938_ccfg_set(TX4938_CCFG_BEOW); + /* enable Timeout BusError */ + if (txx9_ccfg_toeon) + tx4938_ccfg_set(TX4938_CCFG_TOE); + + /* DMA selection */ + txx9_clear64(&tx4938_ccfgptr->pcfg, TX4938_PCFG_DMASEL_ALL); + + /* Use external clock for external arbiter */ + if (!(____raw_readq(&tx4938_ccfgptr->ccfg) & TX4938_CCFG_PCIARB)) + txx9_clear64(&tx4938_ccfgptr->pcfg, TX4938_PCFG_PCICLKEN_ALL); + + printk(KERN_INFO "%s -- %dMHz(M%dMHz) CRIR:%08x CCFG:%llx PCFG:%llx\n", + txx9_pcode_str, + (cpuclk + 500000) / 1000000, + (txx9_master_clock + 500000) / 1000000, + (__u32)____raw_readq(&tx4938_ccfgptr->crir), + (unsigned long long)____raw_readq(&tx4938_ccfgptr->ccfg), + (unsigned long long)____raw_readq(&tx4938_ccfgptr->pcfg)); + + printk(KERN_INFO "%s SDRAMC --", txx9_pcode_str); + for (i = 0; i < 4; i++) { + __u64 cr = TX4938_SDRAMC_CR(i); + unsigned long base, size; + if (!((__u32)cr & 0x00000400)) + continue; /* disabled */ + base = (unsigned long)(cr >> 49) << 21; + size = (((unsigned long)(cr >> 33) & 0x7fff) + 1) << 21; + printk(" CR%d:%016llx", i, (unsigned long long)cr); + tx4938_sdram_resource[i].name = "SDRAM"; + tx4938_sdram_resource[i].start = base; + tx4938_sdram_resource[i].end = base + size - 1; + tx4938_sdram_resource[i].flags = IORESOURCE_MEM; + request_resource(&iomem_resource, &tx4938_sdram_resource[i]); + } + printk(" TR:%09llx\n", + (unsigned long long)____raw_readq(&tx4938_sdramcptr->tr)); + + /* SRAM */ + if (txx9_pcode == 0x4938 && ____raw_readq(&tx4938_sramcptr->cr) & 1) { + unsigned int size = TX4938_SRAM_SIZE; + tx4938_sram_resource.name = "SRAM"; + tx4938_sram_resource.start = + (____raw_readq(&tx4938_sramcptr->cr) >> (39-11)) + & ~(size - 1); + tx4938_sram_resource.end = + tx4938_sram_resource.start + TX4938_SRAM_SIZE - 1; + tx4938_sram_resource.flags = IORESOURCE_MEM; + request_resource(&iomem_resource, &tx4938_sram_resource); + } + + /* TMR */ + /* disable all timers */ + for (i = 0; i < TX4938_NR_TMR; i++) + txx9_tmr_init(TX4938_TMR_REG(i) & 0xfffffffffULL); + + /* DMA */ + for (i = 0; i < 2; i++) + ____raw_writeq(TX4938_DMA_MCR_MSTEN, + (void __iomem *)(TX4938_DMA_REG(i) + 0x50)); + + /* PIO */ + txx9_gpio_init(TX4938_PIO_REG & 0xfffffffffULL, 0, TX4938_NUM_PIO); + __raw_writel(0, &tx4938_pioptr->maskcpu); + __raw_writel(0, &tx4938_pioptr->maskext); + + if (txx9_pcode == 0x4938) { + __u64 pcfg = ____raw_readq(&tx4938_ccfgptr->pcfg); + /* set PCIC1 reset */ + txx9_set64(&tx4938_ccfgptr->clkctr, TX4938_CLKCTR_PCIC1RST); + if (pcfg & (TX4938_PCFG_ETH0_SEL | TX4938_PCFG_ETH1_SEL)) { + mdelay(1); /* at least 128 cpu clock */ + /* clear PCIC1 reset */ + txx9_clear64(&tx4938_ccfgptr->clkctr, + TX4938_CLKCTR_PCIC1RST); + } else { + printk(KERN_INFO "%s: stop PCIC1\n", txx9_pcode_str); + /* stop PCIC1 */ + txx9_set64(&tx4938_ccfgptr->clkctr, + TX4938_CLKCTR_PCIC1CKD); + } + if (!(pcfg & TX4938_PCFG_ETH0_SEL)) { + printk(KERN_INFO "%s: stop ETH0\n", txx9_pcode_str); + txx9_set64(&tx4938_ccfgptr->clkctr, + TX4938_CLKCTR_ETH0RST); + txx9_set64(&tx4938_ccfgptr->clkctr, + TX4938_CLKCTR_ETH0CKD); + } + if (!(pcfg & TX4938_PCFG_ETH1_SEL)) { + printk(KERN_INFO "%s: stop ETH1\n", txx9_pcode_str); + txx9_set64(&tx4938_ccfgptr->clkctr, + TX4938_CLKCTR_ETH1RST); + txx9_set64(&tx4938_ccfgptr->clkctr, + TX4938_CLKCTR_ETH1CKD); + } + } +} + +void __init tx4938_time_init(unsigned int tmrnr) +{ + if (____raw_readq(&tx4938_ccfgptr->ccfg) & TX4938_CCFG_TINTDIS) + txx9_clockevent_init(TX4938_TMR_REG(tmrnr) & 0xfffffffffULL, + TXX9_IRQ_BASE + TX4938_IR_TMR(tmrnr), + TXX9_IMCLK); +} + +void __init tx4938_setup_serial(void) +{ +#ifdef CONFIG_SERIAL_TXX9 + int i; + struct uart_port req; + unsigned int ch_mask = 0; + + if (__raw_readq(&tx4938_ccfgptr->pcfg) & TX4938_PCFG_ETH0_SEL) + ch_mask |= 1 << 1; /* disable SIO1 by PCFG setting */ + for (i = 0; i < 2; i++) { + if ((1 << i) & ch_mask) + continue; + memset(&req, 0, sizeof(req)); + req.line = i; + req.iotype = UPIO_MEM; + req.membase = (unsigned char __iomem *)TX4938_SIO_REG(i); + req.mapbase = TX4938_SIO_REG(i) & 0xfffffffffULL; + req.irq = TXX9_IRQ_BASE + TX4938_IR_SIO(i); + req.flags |= UPF_BUGGY_UART /*HAVE_CTS_LINE*/; + req.uartclk = TXX9_IMCLK; + early_serial_txx9_setup(&req); + } +#endif /* CONFIG_SERIAL_TXX9 */ +} diff --git a/arch/mips/txx9/generic/smsc_fdc37m81x.c b/arch/mips/txx9/generic/smsc_fdc37m81x.c new file mode 100644 index 00000000000..69e487467fa --- /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 diff --git a/arch/mips/txx9/jmr3927/Makefile b/arch/mips/txx9/jmr3927/Makefile new file mode 100644 index 00000000000..ba292c94566 --- /dev/null +++ b/arch/mips/txx9/jmr3927/Makefile @@ -0,0 +1,8 @@ +# +# Makefile for TOSHIBA JMR-TX3927 board +# + +obj-y += prom.o irq.o setup.o +obj-$(CONFIG_KGDB) += kgdb_io.o + +EXTRA_CFLAGS += -Werror diff --git a/arch/mips/txx9/jmr3927/irq.c b/arch/mips/txx9/jmr3927/irq.c new file mode 100644 index 00000000000..070c9a115e5 --- /dev/null +++ b/arch/mips/txx9/jmr3927/irq.c @@ -0,0 +1,171 @@ +/* + * Copyright 2001 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * ahennessy@mvista.com + * + * 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. + * + * Copyright (C) 2000-2001 Toshiba Corporation + * + * 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/sched.h> +#include <linux/types.h> +#include <linux/interrupt.h> + +#include <asm/io.h> +#include <asm/mipsregs.h> +#include <asm/system.h> + +#include <asm/processor.h> +#include <asm/txx9/generic.h> +#include <asm/txx9/jmr3927.h> + +#if JMR3927_IRQ_END > NR_IRQS +#error JMR3927_IRQ_END > NR_IRQS +#endif + +static unsigned char irc_level[TX3927_NUM_IR] = { + 5, 5, 5, 5, 5, 5, /* INT[5:0] */ + 7, 7, /* SIO */ + 5, 5, 5, 0, 0, /* DMA, PIO, PCI */ + 6, 6, 6 /* TMR */ +}; + +/* + * CP0_STATUS is a thread's resource (saved/restored on context switch). + * So disable_irq/enable_irq MUST handle IOC/IRC registers. + */ +static void mask_irq_ioc(unsigned int irq) +{ + /* 0: mask */ + unsigned int irq_nr = irq - JMR3927_IRQ_IOC; + unsigned char imask = jmr3927_ioc_reg_in(JMR3927_IOC_INTM_ADDR); + unsigned int bit = 1 << irq_nr; + jmr3927_ioc_reg_out(imask & ~bit, JMR3927_IOC_INTM_ADDR); + /* flush write buffer */ + (void)jmr3927_ioc_reg_in(JMR3927_IOC_REV_ADDR); +} +static void unmask_irq_ioc(unsigned int irq) +{ + /* 0: mask */ + unsigned int irq_nr = irq - JMR3927_IRQ_IOC; + unsigned char imask = jmr3927_ioc_reg_in(JMR3927_IOC_INTM_ADDR); + unsigned int bit = 1 << irq_nr; + jmr3927_ioc_reg_out(imask | bit, JMR3927_IOC_INTM_ADDR); + /* flush write buffer */ + (void)jmr3927_ioc_reg_in(JMR3927_IOC_REV_ADDR); +} + +static int jmr3927_ioc_irqroute(void) +{ + unsigned char istat = jmr3927_ioc_reg_in(JMR3927_IOC_INTS2_ADDR); + int i; + + for (i = 0; i < JMR3927_NR_IRQ_IOC; i++) { + if (istat & (1 << i)) + return JMR3927_IRQ_IOC + i; + } + return -1; +} + +static int jmr3927_irq_dispatch(int pending) +{ + int irq; + + if ((pending & CAUSEF_IP7) == 0) + return -1; + irq = (pending >> CAUSEB_IP2) & 0x0f; + irq += JMR3927_IRQ_IRC; + if (irq == JMR3927_IRQ_IOCINT) + irq = jmr3927_ioc_irqroute(); + return irq; +} + +#ifdef CONFIG_PCI +static irqreturn_t jmr3927_pcierr_interrupt(int irq, void *dev_id) +{ + printk(KERN_WARNING "PCI error interrupt (irq 0x%x).\n", irq); + printk(KERN_WARNING "pcistat:%02x, lbstat:%04lx\n", + tx3927_pcicptr->pcistat, tx3927_pcicptr->lbstat); + + return IRQ_HANDLED; +} +static struct irqaction pcierr_action = { + .handler = jmr3927_pcierr_interrupt, + .mask = CPU_MASK_NONE, + .name = "PCI error", +}; +#endif + +static void __init jmr3927_irq_init(void); + +void __init jmr3927_irq_setup(void) +{ + txx9_irq_dispatch = jmr3927_irq_dispatch; + /* Now, interrupt control disabled, */ + /* all IRC interrupts are masked, */ + /* all IRC interrupt mode are Low Active. */ + + /* mask all IOC interrupts */ + jmr3927_ioc_reg_out(0, JMR3927_IOC_INTM_ADDR); + /* setup IOC interrupt mode (SOFT:High Active, Others:Low Active) */ + jmr3927_ioc_reg_out(JMR3927_IOC_INTF_SOFT, JMR3927_IOC_INTP_ADDR); + + /* clear PCI Soft interrupts */ + jmr3927_ioc_reg_out(0, JMR3927_IOC_INTS1_ADDR); + /* clear PCI Reset interrupts */ + jmr3927_ioc_reg_out(0, JMR3927_IOC_RESET_ADDR); + + jmr3927_irq_init(); + + /* setup IOC interrupt 1 (PCI, MODEM) */ + set_irq_chained_handler(JMR3927_IRQ_IOCINT, handle_simple_irq); + +#ifdef CONFIG_PCI + setup_irq(JMR3927_IRQ_IRC_PCI, &pcierr_action); +#endif + + /* enable all CPU interrupt bits. */ + set_c0_status(ST0_IM); /* IE bit is still 0. */ +} + +static struct irq_chip jmr3927_irq_ioc = { + .name = "jmr3927_ioc", + .ack = mask_irq_ioc, + .mask = mask_irq_ioc, + .mask_ack = mask_irq_ioc, + .unmask = unmask_irq_ioc, +}; + +static void __init jmr3927_irq_init(void) +{ + u32 i; + + txx9_irq_init(TX3927_IRC_REG); + for (i = 0; i < TXx9_MAX_IR; i++) + txx9_irq_set_pri(i, irc_level[i]); + for (i = JMR3927_IRQ_IOC; i < JMR3927_IRQ_IOC + JMR3927_NR_IRQ_IOC; i++) + set_irq_chip_and_handler(i, &jmr3927_irq_ioc, handle_level_irq); +} diff --git a/arch/mips/txx9/jmr3927/kgdb_io.c b/arch/mips/txx9/jmr3927/kgdb_io.c new file mode 100644 index 00000000000..5bd757e56f7 --- /dev/null +++ b/arch/mips/txx9/jmr3927/kgdb_io.c @@ -0,0 +1,105 @@ +/* + * BRIEF MODULE DESCRIPTION + * Low level uart routines to directly access a TX[34]927 SIO. + * + * Copyright 2001 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * ahennessy@mvista.com or source@mvista.com + * + * Based on arch/mips/ddb5xxx/ddb5477/kgdb_io.c + * + * Copyright (C) 2000-2001 Toshiba Corporation + * + * 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 <asm/txx9/jmr3927.h> + +#define TIMEOUT 0xffffff + +static int remoteDebugInitialized = 0; +static void debugInit(int baud); + +int putDebugChar(unsigned char c) +{ + int i = 0; + + if (!remoteDebugInitialized) { + remoteDebugInitialized = 1; + debugInit(38400); + } + + do { + slow_down(); + i++; + if (i>TIMEOUT) { + break; + } + } while (!(tx3927_sioptr(0)->cisr & TXx927_SICISR_TXALS)); + tx3927_sioptr(0)->tfifo = c; + + return 1; +} + +unsigned char getDebugChar(void) +{ + int i = 0; + int dicr; + char c; + + if (!remoteDebugInitialized) { + remoteDebugInitialized = 1; + debugInit(38400); + } + + /* diable RX int. */ + dicr = tx3927_sioptr(0)->dicr; + tx3927_sioptr(0)->dicr = 0; + + do { + slow_down(); + i++; + if (i>TIMEOUT) { + break; + } + } while (tx3927_sioptr(0)->disr & TXx927_SIDISR_UVALID) + ; + c = tx3927_sioptr(0)->rfifo; + + /* clear RX int. status */ + tx3927_sioptr(0)->disr &= ~TXx927_SIDISR_RDIS; + /* enable RX int. */ + tx3927_sioptr(0)->dicr = dicr; + + return c; +} + +static void debugInit(int baud) +{ + tx3927_sioptr(0)->lcr = 0x020; + tx3927_sioptr(0)->dicr = 0; + tx3927_sioptr(0)->disr = 0x4100; + tx3927_sioptr(0)->cisr = 0x014; + tx3927_sioptr(0)->fcr = 0; + tx3927_sioptr(0)->flcr = 0x02; + tx3927_sioptr(0)->bgr = ((JMR3927_BASE_BAUD + baud / 2) / baud) | + TXx927_SIBGR_BCLK_T0; +} diff --git a/arch/mips/txx9/jmr3927/prom.c b/arch/mips/txx9/jmr3927/prom.c new file mode 100644 index 00000000000..2cadb423fac --- /dev/null +++ b/arch/mips/txx9/jmr3927/prom.c @@ -0,0 +1,76 @@ +/* + * BRIEF MODULE DESCRIPTION + * PROM library initialisation code, assuming a version of + * pmon is the boot code. + * + * Copyright 2001 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * ahennessy@mvista.com + * + * Based on arch/mips/au1000/common/prom.c + * + * This file was derived from Carsten Langgaard's + * arch/mips/mips-boards/xx files. + * + * Carsten Langgaard, carstenl@mips.com + * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved. + * + * 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 <asm/bootinfo.h> +#include <asm/txx9/generic.h> +#include <asm/txx9/jmr3927.h> + +#define TIMEOUT 0xffffff + +void +prom_putchar(char c) +{ + int i = 0; + + do { + i++; + if (i>TIMEOUT) + break; + } while (!(tx3927_sioptr(1)->cisr & TXx927_SICISR_TXALS)); + tx3927_sioptr(1)->tfifo = c; + return; +} + +void +puts(const char *cp) +{ + while (*cp) + prom_putchar(*cp++); + prom_putchar('\r'); + prom_putchar('\n'); +} + +void __init jmr3927_prom_init(void) +{ + /* CCFG */ + if ((tx3927_ccfgptr->ccfg & TX3927_CCFG_TLBOFF) == 0) + puts("Warning: TX3927 TLB off\n"); + + prom_init_cmdline(); + add_memory_region(0, JMR3927_SDRAM_SIZE, BOOT_MEM_RAM); +} diff --git a/arch/mips/txx9/jmr3927/setup.c b/arch/mips/txx9/jmr3927/setup.c new file mode 100644 index 00000000000..03647ebe413 --- /dev/null +++ b/arch/mips/txx9/jmr3927/setup.c @@ -0,0 +1,367 @@ +/* + * 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. + * + * Copyright 2001 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * ahennessy@mvista.com + * + * Copyright (C) 2000-2001 Toshiba Corporation + * Copyright (C) 2007 Ralf Baechle (ralf@linux-mips.org) + */ + +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/ioport.h> +#include <linux/delay.h> +#include <linux/pm.h> +#include <linux/platform_device.h> +#include <linux/gpio.h> +#ifdef CONFIG_SERIAL_TXX9 +#include <linux/serial_core.h> +#endif +#include <asm/txx9tmr.h> +#include <asm/txx9pio.h> +#include <asm/reboot.h> +#include <asm/txx9/generic.h> +#include <asm/txx9/pci.h> +#include <asm/txx9/jmr3927.h> +#include <asm/mipsregs.h> + +extern void puts(const char *cp); + +/* don't enable - see errata */ +static int jmr3927_ccfg_toeon; + +static inline void do_reset(void) +{ +#if 1 /* Resetting PCI bus */ + jmr3927_ioc_reg_out(0, JMR3927_IOC_RESET_ADDR); + jmr3927_ioc_reg_out(JMR3927_IOC_RESET_PCI, JMR3927_IOC_RESET_ADDR); + (void)jmr3927_ioc_reg_in(JMR3927_IOC_RESET_ADDR); /* flush WB */ + mdelay(1); + jmr3927_ioc_reg_out(0, JMR3927_IOC_RESET_ADDR); +#endif + jmr3927_ioc_reg_out(JMR3927_IOC_RESET_CPU, JMR3927_IOC_RESET_ADDR); +} + +static void jmr3927_machine_restart(char *command) +{ + local_irq_disable(); + puts("Rebooting..."); + do_reset(); +} + +static void jmr3927_machine_halt(void) +{ + puts("JMR-TX3927 halted.\n"); + while (1); +} + +static void jmr3927_machine_power_off(void) +{ + puts("JMR-TX3927 halted. Please turn off the power.\n"); + while (1); +} + +static void __init jmr3927_time_init(void) +{ + txx9_clockevent_init(TX3927_TMR_REG(0), + TXX9_IRQ_BASE + JMR3927_IRQ_IRC_TMR(0), + JMR3927_IMCLK); + txx9_clocksource_init(TX3927_TMR_REG(1), JMR3927_IMCLK); +} + +#define DO_WRITE_THROUGH +#define DO_ENABLE_CACHE + +static void jmr3927_board_init(void); + +static void __init jmr3927_mem_setup(void) +{ + char *argptr; + + set_io_port_base(JMR3927_PORT_BASE + JMR3927_PCIIO); + + _machine_restart = jmr3927_machine_restart; + _machine_halt = jmr3927_machine_halt; + pm_power_off = jmr3927_machine_power_off; + + /* Reboot on panic */ + panic_timeout = 180; + + /* cache setup */ + { + unsigned int conf; +#ifdef DO_ENABLE_CACHE + int mips_ic_disable = 0, mips_dc_disable = 0; +#else + int mips_ic_disable = 1, mips_dc_disable = 1; +#endif +#ifdef DO_WRITE_THROUGH + int mips_config_cwfon = 0; + int mips_config_wbon = 0; +#else + int mips_config_cwfon = 1; + int mips_config_wbon = 1; +#endif + + conf = read_c0_conf(); + conf &= ~(TX39_CONF_ICE | TX39_CONF_DCE | TX39_CONF_WBON | TX39_CONF_CWFON); + conf |= mips_ic_disable ? 0 : TX39_CONF_ICE; + conf |= mips_dc_disable ? 0 : TX39_CONF_DCE; + conf |= mips_config_wbon ? TX39_CONF_WBON : 0; + conf |= mips_config_cwfon ? TX39_CONF_CWFON : 0; + + write_c0_conf(conf); + write_c0_cache(0); + } + + /* initialize board */ + jmr3927_board_init(); + + argptr = prom_getcmdline(); + + if ((argptr = strstr(argptr, "toeon")) != NULL) + jmr3927_ccfg_toeon = 1; + argptr = prom_getcmdline(); + if ((argptr = strstr(argptr, "ip=")) == NULL) { + argptr = prom_getcmdline(); + strcat(argptr, " ip=bootp"); + } + +#ifdef CONFIG_SERIAL_TXX9 + { + extern int early_serial_txx9_setup(struct uart_port *port); + int i; + struct uart_port req; + for(i = 0; i < 2; i++) { + memset(&req, 0, sizeof(req)); + req.line = i; + req.iotype = UPIO_MEM; + req.membase = (unsigned char __iomem *)TX3927_SIO_REG(i); + req.mapbase = TX3927_SIO_REG(i); + req.irq = i == 0 ? + JMR3927_IRQ_IRC_SIO0 : JMR3927_IRQ_IRC_SIO1; + if (i == 0) + req.flags |= UPF_BUGGY_UART /*HAVE_CTS_LINE*/; + req.uartclk = JMR3927_IMCLK; + early_serial_txx9_setup(&req); + } + } +#ifdef CONFIG_SERIAL_TXX9_CONSOLE + argptr = prom_getcmdline(); + if ((argptr = strstr(argptr, "console=")) == NULL) { + argptr = prom_getcmdline(); + strcat(argptr, " console=ttyS1,115200"); + } +#endif +#endif +} + +static void tx3927_setup(void); + +static void __init jmr3927_pci_setup(void) +{ +#ifdef CONFIG_PCI + int extarb = !(tx3927_ccfgptr->ccfg & TX3927_CCFG_PCIXARB); + struct pci_controller *c; + + c = txx9_alloc_pci_controller(&txx9_primary_pcic, + JMR3927_PCIMEM, JMR3927_PCIMEM_SIZE, + JMR3927_PCIIO, JMR3927_PCIIO_SIZE); + register_pci_controller(c); + if (!extarb) { + /* Reset PCI Bus */ + jmr3927_ioc_reg_out(0, JMR3927_IOC_RESET_ADDR); + udelay(100); + jmr3927_ioc_reg_out(JMR3927_IOC_RESET_PCI, + JMR3927_IOC_RESET_ADDR); + udelay(100); + jmr3927_ioc_reg_out(0, JMR3927_IOC_RESET_ADDR); + } + tx3927_pcic_setup(c, JMR3927_SDRAM_SIZE, extarb); +#endif /* CONFIG_PCI */ +} + +static void __init jmr3927_board_init(void) +{ + tx3927_setup(); + jmr3927_pci_setup(); + + /* SIO0 DTR on */ + jmr3927_ioc_reg_out(0, JMR3927_IOC_DTR_ADDR); + + jmr3927_led_set(0); + + printk("JMR-TX3927 (Rev %d) --- IOC(Rev %d) DIPSW:%d,%d,%d,%d\n", + jmr3927_ioc_reg_in(JMR3927_IOC_BREV_ADDR) & JMR3927_REV_MASK, + jmr3927_ioc_reg_in(JMR3927_IOC_REV_ADDR) & JMR3927_REV_MASK, + jmr3927_dipsw1(), jmr3927_dipsw2(), + jmr3927_dipsw3(), jmr3927_dipsw4()); +} + +static void __init tx3927_setup(void) +{ + int i; + + txx9_cpu_clock = JMR3927_CORECLK; + txx9_gbus_clock = JMR3927_GBUSCLK; + /* SDRAMC are configured by PROM */ + + /* ROMC */ + tx3927_romcptr->cr[1] = JMR3927_ROMCE1 | 0x00030048; + tx3927_romcptr->cr[2] = JMR3927_ROMCE2 | 0x000064c8; + tx3927_romcptr->cr[3] = JMR3927_ROMCE3 | 0x0003f698; + tx3927_romcptr->cr[5] = JMR3927_ROMCE5 | 0x0000f218; + + /* CCFG */ + /* enable Timeout BusError */ + if (jmr3927_ccfg_toeon) + tx3927_ccfgptr->ccfg |= TX3927_CCFG_TOE; + + /* clear BusErrorOnWrite flag */ + tx3927_ccfgptr->ccfg &= ~TX3927_CCFG_BEOW; + /* Disable PCI snoop */ + tx3927_ccfgptr->ccfg &= ~TX3927_CCFG_PSNP; + /* do reset on watchdog */ + tx3927_ccfgptr->ccfg |= TX3927_CCFG_WR; + +#ifdef DO_WRITE_THROUGH + /* Enable PCI SNOOP - with write through only */ + tx3927_ccfgptr->ccfg |= TX3927_CCFG_PSNP; +#endif + + /* Pin selection */ + tx3927_ccfgptr->pcfg &= ~TX3927_PCFG_SELALL; + tx3927_ccfgptr->pcfg |= + TX3927_PCFG_SELSIOC(0) | TX3927_PCFG_SELSIO_ALL | + (TX3927_PCFG_SELDMA_ALL & ~TX3927_PCFG_SELDMA(1)); + + printk("TX3927 -- CRIR:%08lx CCFG:%08lx PCFG:%08lx\n", + tx3927_ccfgptr->crir, + tx3927_ccfgptr->ccfg, tx3927_ccfgptr->pcfg); + + /* TMR */ + for (i = 0; i < TX3927_NR_TMR; i++) + txx9_tmr_init(TX3927_TMR_REG(i)); + + /* DMA */ + tx3927_dmaptr->mcr = 0; + for (i = 0; i < ARRAY_SIZE(tx3927_dmaptr->ch); i++) { + /* reset channel */ + tx3927_dmaptr->ch[i].ccr = TX3927_DMA_CCR_CHRST; + tx3927_dmaptr->ch[i].ccr = 0; + } + /* enable DMA */ +#ifdef __BIG_ENDIAN + tx3927_dmaptr->mcr = TX3927_DMA_MCR_MSTEN; +#else + tx3927_dmaptr->mcr = TX3927_DMA_MCR_MSTEN | TX3927_DMA_MCR_LE; +#endif + + /* PIO */ + /* PIO[15:12] connected to LEDs */ + __raw_writel(0x0000f000, &tx3927_pioptr->dir); + __raw_writel(0, &tx3927_pioptr->maskcpu); + __raw_writel(0, &tx3927_pioptr->maskext); + txx9_gpio_init(TX3927_PIO_REG, 0, 16); + gpio_request(11, "dipsw1"); + gpio_request(10, "dipsw2"); + { + unsigned int conf; + + conf = read_c0_conf(); + if (!(conf & TX39_CONF_ICE)) + printk("TX3927 I-Cache disabled.\n"); + if (!(conf & TX39_CONF_DCE)) + printk("TX3927 D-Cache disabled.\n"); + else if (!(conf & TX39_CONF_WBON)) + printk("TX3927 D-Cache WriteThrough.\n"); + else if (!(conf & TX39_CONF_CWFON)) + printk("TX3927 D-Cache WriteBack.\n"); + else + printk("TX3927 D-Cache WriteBack (CWF) .\n"); + } +} + +/* This trick makes rtc-ds1742 driver usable as is. */ +static unsigned long jmr3927_swizzle_addr_b(unsigned long port) +{ + if ((port & 0xffff0000) != JMR3927_IOC_NVRAMB_ADDR) + return port; + port = (port & 0xffff0000) | (port & 0x7fff << 1); +#ifdef __BIG_ENDIAN + return port; +#else + return port | 1; +#endif +} + +static int __init jmr3927_rtc_init(void) +{ + static struct resource __initdata res = { + .start = JMR3927_IOC_NVRAMB_ADDR - IO_BASE, + .end = JMR3927_IOC_NVRAMB_ADDR - IO_BASE + 0x800 - 1, + .flags = IORESOURCE_MEM, + }; + struct platform_device *dev; + dev = platform_device_register_simple("rtc-ds1742", -1, &res, 1); + return IS_ERR(dev) ? PTR_ERR(dev) : 0; +} + +/* Watchdog support */ + +static int __init txx9_wdt_init(unsigned long base) +{ + struct resource res = { + .start = base, + .end = base + 0x100 - 1, + .flags = IORESOURCE_MEM, + }; + struct platform_device *dev = + platform_device_register_simple("txx9wdt", -1, &res, 1); + return IS_ERR(dev) ? PTR_ERR(dev) : 0; +} + +static int __init jmr3927_wdt_init(void) +{ + return txx9_wdt_init(TX3927_TMR_REG(2)); +} + +static void __init jmr3927_device_init(void) +{ + __swizzle_addr_b = jmr3927_swizzle_addr_b; + jmr3927_rtc_init(); + jmr3927_wdt_init(); +} + +struct txx9_board_vec jmr3927_vec __initdata = { + .system = "Toshiba JMR_TX3927", + .prom_init = jmr3927_prom_init, + .mem_setup = jmr3927_mem_setup, + .irq_setup = jmr3927_irq_setup, + .time_init = jmr3927_time_init, + .device_init = jmr3927_device_init, +#ifdef CONFIG_PCI + .pci_map_irq = jmr3927_pci_map_irq, +#endif +}; diff --git a/arch/mips/txx9/rbtx4927/Makefile b/arch/mips/txx9/rbtx4927/Makefile new file mode 100644 index 00000000000..f3e1f597b4f --- /dev/null +++ b/arch/mips/txx9/rbtx4927/Makefile @@ -0,0 +1,3 @@ +obj-y += prom.o setup.o irq.o + +EXTRA_CFLAGS += -Werror diff --git a/arch/mips/txx9/rbtx4927/irq.c b/arch/mips/txx9/rbtx4927/irq.c new file mode 100644 index 00000000000..cd748a93032 --- /dev/null +++ b/arch/mips/txx9/rbtx4927/irq.c @@ -0,0 +1,197 @@ +/* + * Toshiba RBTX4927 specific interrupt handlers + * + * 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. + */ +/* +IRQ Device +00 RBTX4927-ISA/00 +01 RBTX4927-ISA/01 PS2/Keyboard +02 RBTX4927-ISA/02 Cascade RBTX4927-ISA (irqs 8-15) +03 RBTX4927-ISA/03 +04 RBTX4927-ISA/04 +05 RBTX4927-ISA/05 +06 RBTX4927-ISA/06 +07 RBTX4927-ISA/07 +08 RBTX4927-ISA/08 +09 RBTX4927-ISA/09 +10 RBTX4927-ISA/10 +11 RBTX4927-ISA/11 +12 RBTX4927-ISA/12 PS2/Mouse (not supported at this time) +13 RBTX4927-ISA/13 +14 RBTX4927-ISA/14 IDE +15 RBTX4927-ISA/15 + +16 TX4927-CP0/00 Software 0 +17 TX4927-CP0/01 Software 1 +18 TX4927-CP0/02 Cascade TX4927-CP0 +19 TX4927-CP0/03 Multiplexed -- do not use +20 TX4927-CP0/04 Multiplexed -- do not use +21 TX4927-CP0/05 Multiplexed -- do not use +22 TX4927-CP0/06 Multiplexed -- do not use +23 TX4927-CP0/07 CPU TIMER + +24 TX4927-PIC/00 +25 TX4927-PIC/01 +26 TX4927-PIC/02 +27 TX4927-PIC/03 Cascade RBTX4927-IOC +28 TX4927-PIC/04 +29 TX4927-PIC/05 RBTX4927 RTL-8019AS ethernet +30 TX4927-PIC/06 +31 TX4927-PIC/07 +32 TX4927-PIC/08 TX4927 SerialIO Channel 0 +33 TX4927-PIC/09 TX4927 SerialIO Channel 1 +34 TX4927-PIC/10 +35 TX4927-PIC/11 +36 TX4927-PIC/12 +37 TX4927-PIC/13 +38 TX4927-PIC/14 +39 TX4927-PIC/15 +40 TX4927-PIC/16 TX4927 PCI PCI-C +41 TX4927-PIC/17 +42 TX4927-PIC/18 +43 TX4927-PIC/19 +44 TX4927-PIC/20 +45 TX4927-PIC/21 +46 TX4927-PIC/22 TX4927 PCI PCI-ERR +47 TX4927-PIC/23 TX4927 PCI PCI-PMA (not used) +48 TX4927-PIC/24 +49 TX4927-PIC/25 +50 TX4927-PIC/26 +51 TX4927-PIC/27 +52 TX4927-PIC/28 +53 TX4927-PIC/29 +54 TX4927-PIC/30 +55 TX4927-PIC/31 + +56 RBTX4927-IOC/00 FPCIB0 PCI-D PJ4/A PJ5/B SB/C PJ6/D PJ7/A (SouthBridge/NotUsed) [RTL-8139=PJ4] +57 RBTX4927-IOC/01 FPCIB0 PCI-C PJ4/D PJ5/A SB/B PJ6/C PJ7/D (SouthBridge/NotUsed) [RTL-8139=PJ5] +58 RBTX4927-IOC/02 FPCIB0 PCI-B PJ4/C PJ5/D SB/A PJ6/B PJ7/C (SouthBridge/IDE/pin=1,INTR) [RTL-8139=NotSupported] +59 RBTX4927-IOC/03 FPCIB0 PCI-A PJ4/B PJ5/C SB/D PJ6/A PJ7/B (SouthBridge/USB/pin=4) [RTL-8139=PJ6] +60 RBTX4927-IOC/04 +61 RBTX4927-IOC/05 +62 RBTX4927-IOC/06 +63 RBTX4927-IOC/07 + +NOTES: +SouthBridge/INTR is mapped to SouthBridge/A=PCI-B/#58 +SouthBridge/ISA/pin=0 no pci irq used by this device +SouthBridge/IDE/pin=1 no pci irq used by this device, using INTR via ISA IRQ14 +SouthBridge/USB/pin=4 using pci irq SouthBridge/D=PCI-A=#59 +SouthBridge/PMC/pin=0 no pci irq used by this device +SuperIO/PS2/Keyboard, using INTR via ISA IRQ1 +SuperIO/PS2/Mouse, using INTR via ISA IRQ12 (mouse not currently supported) +JP7 is not bus master -- do NOT use -- only 4 pci bus master's allowed -- SouthBridge, JP4, JP5, JP6 +*/ + +#include <linux/init.h> +#include <linux/types.h> +#include <linux/interrupt.h> +#include <asm/io.h> +#include <asm/mipsregs.h> +#include <asm/txx9/generic.h> +#include <asm/txx9/rbtx4927.h> + +static void toshiba_rbtx4927_irq_ioc_enable(unsigned int irq); +static void toshiba_rbtx4927_irq_ioc_disable(unsigned int irq); + +#define TOSHIBA_RBTX4927_IOC_NAME "RBTX4927-IOC" +static struct irq_chip toshiba_rbtx4927_irq_ioc_type = { + .name = TOSHIBA_RBTX4927_IOC_NAME, + .ack = toshiba_rbtx4927_irq_ioc_disable, + .mask = toshiba_rbtx4927_irq_ioc_disable, + .mask_ack = toshiba_rbtx4927_irq_ioc_disable, + .unmask = toshiba_rbtx4927_irq_ioc_enable, +}; + +static int toshiba_rbtx4927_irq_nested(int sw_irq) +{ + u8 level3; + + level3 = readb(rbtx4927_imstat_addr) & 0x1f; + if (level3) + sw_irq = RBTX4927_IRQ_IOC + fls(level3) - 1; + return (sw_irq); +} + +static void __init toshiba_rbtx4927_irq_ioc_init(void) +{ + int i; + + for (i = RBTX4927_IRQ_IOC; + i < RBTX4927_IRQ_IOC + RBTX4927_NR_IRQ_IOC; i++) + set_irq_chip_and_handler(i, &toshiba_rbtx4927_irq_ioc_type, + handle_level_irq); + set_irq_chained_handler(RBTX4927_IRQ_IOCINT, handle_simple_irq); +} + +static void toshiba_rbtx4927_irq_ioc_enable(unsigned int irq) +{ + unsigned char v; + + v = readb(rbtx4927_imask_addr); + v |= (1 << (irq - RBTX4927_IRQ_IOC)); + writeb(v, rbtx4927_imask_addr); +} + +static void toshiba_rbtx4927_irq_ioc_disable(unsigned int irq) +{ + unsigned char v; + + v = readb(rbtx4927_imask_addr); + v &= ~(1 << (irq - RBTX4927_IRQ_IOC)); + writeb(v, rbtx4927_imask_addr); + mmiowb(); +} + + +static int rbtx4927_irq_dispatch(int pending) +{ + int irq; + + if (pending & STATUSF_IP7) /* cpu timer */ + irq = MIPS_CPU_IRQ_BASE + 7; + else if (pending & STATUSF_IP2) { /* tx4927 pic */ + irq = txx9_irq(); + if (irq == RBTX4927_IRQ_IOCINT) + irq = toshiba_rbtx4927_irq_nested(irq); + } else if (pending & STATUSF_IP0) /* user line 0 */ + irq = MIPS_CPU_IRQ_BASE + 0; + else if (pending & STATUSF_IP1) /* user line 1 */ + irq = MIPS_CPU_IRQ_BASE + 1; + else + irq = -1; + return irq; +} + +void __init rbtx4927_irq_setup(void) +{ + txx9_irq_dispatch = rbtx4927_irq_dispatch; + tx4927_irq_init(); + toshiba_rbtx4927_irq_ioc_init(); + /* Onboard 10M Ether: High Active */ + set_irq_type(RBTX4927_RTL_8019_IRQ, IRQF_TRIGGER_HIGH); +} diff --git a/arch/mips/txx9/rbtx4927/prom.c b/arch/mips/txx9/rbtx4927/prom.c new file mode 100644 index 00000000000..5c0de54ebdd --- /dev/null +++ b/arch/mips/txx9/rbtx4927/prom.c @@ -0,0 +1,41 @@ +/* + * rbtx4927 specific prom routines + * + * Author: MontaVista Software, Inc. + * source@mvista.com + * + * Copyright 2001-2002 MontaVista Software Inc. + * + * Copyright (C) 2004 MontaVista Software Inc. + * Author: Manish Lachwani, mlachwani@mvista.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 <asm/bootinfo.h> +#include <asm/txx9/generic.h> +#include <asm/txx9/rbtx4927.h> + +void __init rbtx4927_prom_init(void) +{ + prom_init_cmdline(); + add_memory_region(0, tx4927_get_mem_size(), BOOT_MEM_RAM); +} diff --git a/arch/mips/txx9/rbtx4927/setup.c b/arch/mips/txx9/rbtx4927/setup.c new file mode 100644 index 00000000000..3da20ea3e55 --- /dev/null +++ b/arch/mips/txx9/rbtx4927/setup.c @@ -0,0 +1,406 @@ +/* + * Toshiba rbtx4927 specific setup + * + * Author: MontaVista Software, Inc. + * source@mvista.com + * + * Copyright 2001-2002 MontaVista Software Inc. + * + * Copyright (C) 1996, 97, 2001, 04 Ralf Baechle (ralf@linux-mips.org) + * Copyright (C) 2000 RidgeRun, Inc. + * Author: RidgeRun, Inc. + * glonnon@ridgerun.com, skranz@ridgerun.com, stevej@ridgerun.com + * + * Copyright 2001 MontaVista Software Inc. + * Author: jsun@mvista.com or jsun@junsun.net + * + * Copyright 2002 MontaVista Software Inc. + * Author: Michael Pruznick, michael_pruznick@mvista.com + * + * Copyright (C) 2000-2001 Toshiba Corporation + * + * Copyright (C) 2004 MontaVista Software Inc. + * Author: Manish Lachwani, mlachwani@mvista.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/kernel.h> +#include <linux/types.h> +#include <linux/ioport.h> +#include <linux/interrupt.h> +#include <linux/pm.h> +#include <linux/platform_device.h> +#include <linux/delay.h> +#include <asm/io.h> +#include <asm/processor.h> +#include <asm/reboot.h> +#include <asm/txx9/generic.h> +#include <asm/txx9/pci.h> +#include <asm/txx9/rbtx4927.h> +#include <asm/txx9/tx4938.h> /* for TX4937 */ + +#ifdef CONFIG_PCI +static void __init tx4927_pci_setup(void) +{ + int extarb = !(__raw_readq(&tx4927_ccfgptr->ccfg) & TX4927_CCFG_PCIARB); + struct pci_controller *c = &txx9_primary_pcic; + + register_pci_controller(c); + + if (__raw_readq(&tx4927_ccfgptr->ccfg) & TX4927_CCFG_PCI66) + txx9_pci_option = + (txx9_pci_option & ~TXX9_PCI_OPT_CLK_MASK) | + TXX9_PCI_OPT_CLK_66; /* already configured */ + + /* Reset PCI Bus */ + writeb(1, rbtx4927_pcireset_addr); + /* Reset PCIC */ + txx9_set64(&tx4927_ccfgptr->clkctr, TX4927_CLKCTR_PCIRST); + if ((txx9_pci_option & TXX9_PCI_OPT_CLK_MASK) == + TXX9_PCI_OPT_CLK_66) + tx4927_pciclk66_setup(); + mdelay(10); + /* clear PCIC reset */ + txx9_clear64(&tx4927_ccfgptr->clkctr, TX4927_CLKCTR_PCIRST); + writeb(0, rbtx4927_pcireset_addr); + iob(); + + tx4927_report_pciclk(); + tx4927_pcic_setup(tx4927_pcicptr, c, extarb); + if ((txx9_pci_option & TXX9_PCI_OPT_CLK_MASK) == + TXX9_PCI_OPT_CLK_AUTO && + txx9_pci66_check(c, 0, 0)) { + /* Reset PCI Bus */ + writeb(1, rbtx4927_pcireset_addr); + /* Reset PCIC */ + txx9_set64(&tx4927_ccfgptr->clkctr, TX4927_CLKCTR_PCIRST); + tx4927_pciclk66_setup(); + mdelay(10); + /* clear PCIC reset */ + txx9_clear64(&tx4927_ccfgptr->clkctr, TX4927_CLKCTR_PCIRST); + writeb(0, rbtx4927_pcireset_addr); + iob(); + /* Reinitialize PCIC */ + tx4927_report_pciclk(); + tx4927_pcic_setup(tx4927_pcicptr, c, extarb); + } +} + +static void __init tx4937_pci_setup(void) +{ + int extarb = !(__raw_readq(&tx4938_ccfgptr->ccfg) & TX4938_CCFG_PCIARB); + struct pci_controller *c = &txx9_primary_pcic; + + register_pci_controller(c); + + if (__raw_readq(&tx4938_ccfgptr->ccfg) & TX4938_CCFG_PCI66) + txx9_pci_option = + (txx9_pci_option & ~TXX9_PCI_OPT_CLK_MASK) | + TXX9_PCI_OPT_CLK_66; /* already configured */ + + /* Reset PCI Bus */ + writeb(1, rbtx4927_pcireset_addr); + /* Reset PCIC */ + txx9_set64(&tx4938_ccfgptr->clkctr, TX4938_CLKCTR_PCIRST); + if ((txx9_pci_option & TXX9_PCI_OPT_CLK_MASK) == + TXX9_PCI_OPT_CLK_66) + tx4938_pciclk66_setup(); + mdelay(10); + /* clear PCIC reset */ + txx9_clear64(&tx4938_ccfgptr->clkctr, TX4938_CLKCTR_PCIRST); + writeb(0, rbtx4927_pcireset_addr); + iob(); + + tx4938_report_pciclk(); + tx4927_pcic_setup(tx4938_pcicptr, c, extarb); + if ((txx9_pci_option & TXX9_PCI_OPT_CLK_MASK) == + TXX9_PCI_OPT_CLK_AUTO && + txx9_pci66_check(c, 0, 0)) { + /* Reset PCI Bus */ + writeb(1, rbtx4927_pcireset_addr); + /* Reset PCIC */ + txx9_set64(&tx4938_ccfgptr->clkctr, TX4938_CLKCTR_PCIRST); + tx4938_pciclk66_setup(); + mdelay(10); + /* clear PCIC reset */ + txx9_clear64(&tx4938_ccfgptr->clkctr, TX4938_CLKCTR_PCIRST); + writeb(0, rbtx4927_pcireset_addr); + iob(); + /* Reinitialize PCIC */ + tx4938_report_pciclk(); + tx4927_pcic_setup(tx4938_pcicptr, c, extarb); + } +} + +static void __init rbtx4927_arch_init(void) +{ + tx4927_pci_setup(); +} + +static void __init rbtx4937_arch_init(void) +{ + tx4937_pci_setup(); +} +#else +#define rbtx4927_arch_init NULL +#define rbtx4937_arch_init NULL +#endif /* CONFIG_PCI */ + +static void __noreturn wait_forever(void) +{ + while (1) + if (cpu_wait) + (*cpu_wait)(); +} + +static void toshiba_rbtx4927_restart(char *command) +{ + printk(KERN_NOTICE "System Rebooting...\n"); + + /* enable the s/w reset register */ + writeb(1, rbtx4927_softresetlock_addr); + + /* wait for enable to be seen */ + while (!(readb(rbtx4927_softresetlock_addr) & 1)) + ; + + /* do a s/w reset */ + writeb(1, rbtx4927_softreset_addr); + + /* do something passive while waiting for reset */ + local_irq_disable(); + wait_forever(); + /* no return */ +} + +static void toshiba_rbtx4927_halt(void) +{ + printk(KERN_NOTICE "System Halted\n"); + local_irq_disable(); + wait_forever(); + /* no return */ +} + +static void toshiba_rbtx4927_power_off(void) +{ + toshiba_rbtx4927_halt(); + /* no return */ +} + +static void __init rbtx4927_clock_init(void); +static void __init rbtx4937_clock_init(void); + +static void __init rbtx4927_mem_setup(void) +{ + u32 cp0_config; + char *argptr; + + /* f/w leaves this on at startup */ + clear_c0_status(ST0_ERL); + + /* enable caches -- HCP5 does this, pmon does not */ + cp0_config = read_c0_config(); + cp0_config = cp0_config & ~(TX49_CONF_IC | TX49_CONF_DC); + write_c0_config(cp0_config); + + if (TX4927_REV_PCODE() == 0x4927) { + rbtx4927_clock_init(); + tx4927_setup(); + } else { + rbtx4937_clock_init(); + tx4938_setup(); + } + + _machine_restart = toshiba_rbtx4927_restart; + _machine_halt = toshiba_rbtx4927_halt; + pm_power_off = toshiba_rbtx4927_power_off; + +#ifdef CONFIG_PCI + txx9_alloc_pci_controller(&txx9_primary_pcic, + RBTX4927_PCIMEM, RBTX4927_PCIMEM_SIZE, + RBTX4927_PCIIO, RBTX4927_PCIIO_SIZE); +#else + set_io_port_base(KSEG1 + RBTX4927_ISA_IO_OFFSET); +#endif + + tx4927_setup_serial(); +#ifdef CONFIG_SERIAL_TXX9_CONSOLE + argptr = prom_getcmdline(); + if (strstr(argptr, "console=") == NULL) { + strcat(argptr, " console=ttyS0,38400"); + } +#endif + +#ifdef CONFIG_ROOT_NFS + argptr = prom_getcmdline(); + if (strstr(argptr, "root=") == NULL) { + strcat(argptr, " root=/dev/nfs rw"); + } +#endif + +#ifdef CONFIG_IP_PNP + argptr = prom_getcmdline(); + if (strstr(argptr, "ip=") == NULL) { + strcat(argptr, " ip=any"); + } +#endif +} + +static void __init rbtx4927_clock_init(void) +{ + /* + * ASSUMPTION: PCIDIVMODE is configured for PCI 33MHz or 66MHz. + * + * For TX4927: + * PCIDIVMODE[12:11]'s initial value is given by S9[4:3] (ON:0, OFF:1). + * CPU 166MHz: PCI 66MHz : PCIDIVMODE: 00 (1/2.5) + * CPU 200MHz: PCI 66MHz : PCIDIVMODE: 01 (1/3) + * CPU 166MHz: PCI 33MHz : PCIDIVMODE: 10 (1/5) + * CPU 200MHz: PCI 33MHz : PCIDIVMODE: 11 (1/6) + * i.e. S9[3]: ON (83MHz), OFF (100MHz) + */ + switch ((unsigned long)__raw_readq(&tx4927_ccfgptr->ccfg) & + TX4927_CCFG_PCIDIVMODE_MASK) { + case TX4927_CCFG_PCIDIVMODE_2_5: + case TX4927_CCFG_PCIDIVMODE_5: + txx9_cpu_clock = 166666666; /* 166MHz */ + break; + default: + txx9_cpu_clock = 200000000; /* 200MHz */ + } +} + +static void __init rbtx4937_clock_init(void) +{ + /* + * ASSUMPTION: PCIDIVMODE is configured for PCI 33MHz or 66MHz. + * + * For TX4937: + * PCIDIVMODE[12:11]'s initial value is given by S1[5:4] (ON:0, OFF:1) + * PCIDIVMODE[10] is 0. + * CPU 266MHz: PCI 33MHz : PCIDIVMODE: 000 (1/8) + * CPU 266MHz: PCI 66MHz : PCIDIVMODE: 001 (1/4) + * CPU 300MHz: PCI 33MHz : PCIDIVMODE: 010 (1/9) + * CPU 300MHz: PCI 66MHz : PCIDIVMODE: 011 (1/4.5) + * CPU 333MHz: PCI 33MHz : PCIDIVMODE: 100 (1/10) + * CPU 333MHz: PCI 66MHz : PCIDIVMODE: 101 (1/5) + */ + switch ((unsigned long)__raw_readq(&tx4938_ccfgptr->ccfg) & + TX4938_CCFG_PCIDIVMODE_MASK) { + case TX4938_CCFG_PCIDIVMODE_8: + case TX4938_CCFG_PCIDIVMODE_4: + txx9_cpu_clock = 266666666; /* 266MHz */ + break; + case TX4938_CCFG_PCIDIVMODE_9: + case TX4938_CCFG_PCIDIVMODE_4_5: + txx9_cpu_clock = 300000000; /* 300MHz */ + break; + default: + txx9_cpu_clock = 333333333; /* 333MHz */ + } +} + +static void __init rbtx4927_time_init(void) +{ + tx4927_time_init(0); +} + +static int __init toshiba_rbtx4927_rtc_init(void) +{ + struct resource res = { + .start = RBTX4927_BRAMRTC_BASE - IO_BASE, + .end = RBTX4927_BRAMRTC_BASE - IO_BASE + 0x800 - 1, + .flags = IORESOURCE_MEM, + }; + struct platform_device *dev = + platform_device_register_simple("rtc-ds1742", -1, &res, 1); + return IS_ERR(dev) ? PTR_ERR(dev) : 0; +} + +static int __init rbtx4927_ne_init(void) +{ + struct resource res[] = { + { + .start = RBTX4927_RTL_8019_BASE, + .end = RBTX4927_RTL_8019_BASE + 0x20 - 1, + .flags = IORESOURCE_IO, + }, { + .start = RBTX4927_RTL_8019_IRQ, + .flags = IORESOURCE_IRQ, + } + }; + struct platform_device *dev = + platform_device_register_simple("ne", -1, + res, ARRAY_SIZE(res)); + return IS_ERR(dev) ? PTR_ERR(dev) : 0; +} + +/* Watchdog support */ + +static int __init txx9_wdt_init(unsigned long base) +{ + struct resource res = { + .start = base, + .end = base + 0x100 - 1, + .flags = IORESOURCE_MEM, + }; + struct platform_device *dev = + platform_device_register_simple("txx9wdt", -1, &res, 1); + return IS_ERR(dev) ? PTR_ERR(dev) : 0; +} + +static int __init rbtx4927_wdt_init(void) +{ + return txx9_wdt_init(TX4927_TMR_REG(2) & 0xfffffffffULL); +} + +static void __init rbtx4927_device_init(void) +{ + toshiba_rbtx4927_rtc_init(); + rbtx4927_ne_init(); + rbtx4927_wdt_init(); +} + +struct txx9_board_vec rbtx4927_vec __initdata = { + .system = "Toshiba RBTX4927", + .prom_init = rbtx4927_prom_init, + .mem_setup = rbtx4927_mem_setup, + .irq_setup = rbtx4927_irq_setup, + .time_init = rbtx4927_time_init, + .device_init = rbtx4927_device_init, + .arch_init = rbtx4927_arch_init, +#ifdef CONFIG_PCI + .pci_map_irq = rbtx4927_pci_map_irq, +#endif +}; +struct txx9_board_vec rbtx4937_vec __initdata = { + .system = "Toshiba RBTX4937", + .prom_init = rbtx4927_prom_init, + .mem_setup = rbtx4927_mem_setup, + .irq_setup = rbtx4927_irq_setup, + .time_init = rbtx4927_time_init, + .device_init = rbtx4927_device_init, + .arch_init = rbtx4937_arch_init, +#ifdef CONFIG_PCI + .pci_map_irq = rbtx4927_pci_map_irq, +#endif +}; diff --git a/arch/mips/txx9/rbtx4938/Makefile b/arch/mips/txx9/rbtx4938/Makefile new file mode 100644 index 00000000000..9dcc52ae5b9 --- /dev/null +++ b/arch/mips/txx9/rbtx4938/Makefile @@ -0,0 +1,3 @@ +obj-y += prom.o setup.o irq.o spi_eeprom.o + +EXTRA_CFLAGS += -Werror diff --git a/arch/mips/txx9/rbtx4938/irq.c b/arch/mips/txx9/rbtx4938/irq.c new file mode 100644 index 00000000000..3971a061657 --- /dev/null +++ b/arch/mips/txx9/rbtx4938/irq.c @@ -0,0 +1,169 @@ +/* + * Toshiba RBTX4938 specific interrupt handlers + * 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) + */ + +/* +IRQ Device + +16 TX4938-CP0/00 Software 0 +17 TX4938-CP0/01 Software 1 +18 TX4938-CP0/02 Cascade TX4938-CP0 +19 TX4938-CP0/03 Multiplexed -- do not use +20 TX4938-CP0/04 Multiplexed -- do not use +21 TX4938-CP0/05 Multiplexed -- do not use +22 TX4938-CP0/06 Multiplexed -- do not use +23 TX4938-CP0/07 CPU TIMER + +24 TX4938-PIC/00 +25 TX4938-PIC/01 +26 TX4938-PIC/02 Cascade RBTX4938-IOC +27 TX4938-PIC/03 RBTX4938 RTL-8019AS Ethernet +28 TX4938-PIC/04 +29 TX4938-PIC/05 TX4938 ETH1 +30 TX4938-PIC/06 TX4938 ETH0 +31 TX4938-PIC/07 +32 TX4938-PIC/08 TX4938 SIO 0 +33 TX4938-PIC/09 TX4938 SIO 1 +34 TX4938-PIC/10 TX4938 DMA0 +35 TX4938-PIC/11 TX4938 DMA1 +36 TX4938-PIC/12 TX4938 DMA2 +37 TX4938-PIC/13 TX4938 DMA3 +38 TX4938-PIC/14 +39 TX4938-PIC/15 +40 TX4938-PIC/16 TX4938 PCIC +41 TX4938-PIC/17 TX4938 TMR0 +42 TX4938-PIC/18 TX4938 TMR1 +43 TX4938-PIC/19 TX4938 TMR2 +44 TX4938-PIC/20 +45 TX4938-PIC/21 +46 TX4938-PIC/22 TX4938 PCIERR +47 TX4938-PIC/23 +48 TX4938-PIC/24 +49 TX4938-PIC/25 +50 TX4938-PIC/26 +51 TX4938-PIC/27 +52 TX4938-PIC/28 +53 TX4938-PIC/29 +54 TX4938-PIC/30 +55 TX4938-PIC/31 TX4938 SPI + +56 RBTX4938-IOC/00 PCI-D +57 RBTX4938-IOC/01 PCI-C +58 RBTX4938-IOC/02 PCI-B +59 RBTX4938-IOC/03 PCI-A +60 RBTX4938-IOC/04 RTC +61 RBTX4938-IOC/05 ATA +62 RBTX4938-IOC/06 MODEM +63 RBTX4938-IOC/07 SWINT +*/ +#include <linux/init.h> +#include <linux/interrupt.h> +#include <asm/mipsregs.h> +#include <asm/txx9/generic.h> +#include <asm/txx9/rbtx4938.h> + +static void toshiba_rbtx4938_irq_ioc_enable(unsigned int irq); +static void toshiba_rbtx4938_irq_ioc_disable(unsigned int irq); + +#define TOSHIBA_RBTX4938_IOC_NAME "RBTX4938-IOC" +static struct irq_chip toshiba_rbtx4938_irq_ioc_type = { + .name = TOSHIBA_RBTX4938_IOC_NAME, + .ack = toshiba_rbtx4938_irq_ioc_disable, + .mask = toshiba_rbtx4938_irq_ioc_disable, + .mask_ack = toshiba_rbtx4938_irq_ioc_disable, + .unmask = toshiba_rbtx4938_irq_ioc_enable, +}; + +static int toshiba_rbtx4938_irq_nested(int sw_irq) +{ + u8 level3; + + level3 = readb(rbtx4938_imstat_addr); + if (level3) + /* must use fls so onboard ATA has priority */ + sw_irq = RBTX4938_IRQ_IOC + fls(level3) - 1; + return sw_irq; +} + +/**********************************************************************************/ +/* Functions for ioc */ +/**********************************************************************************/ +static void __init +toshiba_rbtx4938_irq_ioc_init(void) +{ + int i; + + for (i = RBTX4938_IRQ_IOC; + i < RBTX4938_IRQ_IOC + RBTX4938_NR_IRQ_IOC; i++) + set_irq_chip_and_handler(i, &toshiba_rbtx4938_irq_ioc_type, + handle_level_irq); + + set_irq_chained_handler(RBTX4938_IRQ_IOCINT, handle_simple_irq); +} + +static void +toshiba_rbtx4938_irq_ioc_enable(unsigned int irq) +{ + unsigned char v; + + v = readb(rbtx4938_imask_addr); + v |= (1 << (irq - RBTX4938_IRQ_IOC)); + writeb(v, rbtx4938_imask_addr); + mmiowb(); +} + +static void +toshiba_rbtx4938_irq_ioc_disable(unsigned int irq) +{ + unsigned char v; + + v = readb(rbtx4938_imask_addr); + v &= ~(1 << (irq - RBTX4938_IRQ_IOC)); + writeb(v, rbtx4938_imask_addr); + mmiowb(); +} + +static int rbtx4938_irq_dispatch(int pending) +{ + int irq; + + if (pending & STATUSF_IP7) + irq = MIPS_CPU_IRQ_BASE + 7; + else if (pending & STATUSF_IP2) { + irq = txx9_irq(); + if (irq == RBTX4938_IRQ_IOCINT) + irq = toshiba_rbtx4938_irq_nested(irq); + } else if (pending & STATUSF_IP1) + irq = MIPS_CPU_IRQ_BASE + 0; + else if (pending & STATUSF_IP0) + irq = MIPS_CPU_IRQ_BASE + 1; + else + irq = -1; + return irq; +} + +void __init rbtx4938_irq_setup(void) +{ + txx9_irq_dispatch = rbtx4938_irq_dispatch; + /* Now, interrupt control disabled, */ + /* all IRC interrupts are masked, */ + /* all IRC interrupt mode are Low Active. */ + + /* mask all IOC interrupts */ + writeb(0, rbtx4938_imask_addr); + + /* clear SoftInt interrupts */ + writeb(0, rbtx4938_softint_addr); + tx4938_irq_init(); + toshiba_rbtx4938_irq_ioc_init(); + /* Onboard 10M Ether: High Active */ + set_irq_type(RBTX4938_IRQ_ETHER, IRQF_TRIGGER_HIGH); +} diff --git a/arch/mips/txx9/rbtx4938/prom.c b/arch/mips/txx9/rbtx4938/prom.c new file mode 100644 index 00000000000..ee189519ce5 --- /dev/null +++ b/arch/mips/txx9/rbtx4938/prom.c @@ -0,0 +1,25 @@ +/* + * rbtx4938 specific prom routines + * 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/bootmem.h> +#include <asm/bootinfo.h> +#include <asm/txx9/generic.h> +#include <asm/txx9/rbtx4938.h> + +void __init rbtx4938_prom_init(void) +{ +#ifndef CONFIG_TX4938_NAND_BOOT + prom_init_cmdline(); +#endif + add_memory_region(0, tx4938_get_mem_size(), BOOT_MEM_RAM); +} diff --git a/arch/mips/txx9/rbtx4938/setup.c b/arch/mips/txx9/rbtx4938/setup.c new file mode 100644 index 00000000000..6c2b99bb8af --- /dev/null +++ b/arch/mips/txx9/rbtx4938/setup.c @@ -0,0 +1,412 @@ +/* + * Setup pointers to hardware-dependent routines. + * 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/ioport.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/console.h> +#include <linux/pm.h> +#include <linux/platform_device.h> +#include <linux/gpio.h> + +#include <asm/reboot.h> +#include <asm/io.h> +#include <asm/txx9/generic.h> +#include <asm/txx9/pci.h> +#include <asm/txx9/rbtx4938.h> +#include <linux/spi/spi.h> +#include <asm/txx9/spi.h> +#include <asm/txx9pio.h> + +static void rbtx4938_machine_halt(void) +{ + printk(KERN_NOTICE "System Halted\n"); + local_irq_disable(); + + while (1) + __asm__(".set\tmips3\n\t" + "wait\n\t" + ".set\tmips0"); +} + +static void rbtx4938_machine_power_off(void) +{ + rbtx4938_machine_halt(); + /* no return */ +} + +static void rbtx4938_machine_restart(char *command) +{ + local_irq_disable(); + + printk("Rebooting..."); + writeb(1, rbtx4938_softresetlock_addr); + writeb(1, rbtx4938_sfvol_addr); + writeb(1, rbtx4938_softreset_addr); + while(1) + ; +} + +static void __init rbtx4938_pci_setup(void) +{ +#ifdef CONFIG_PCI + int extarb = !(__raw_readq(&tx4938_ccfgptr->ccfg) & TX4938_CCFG_PCIARB); + struct pci_controller *c = &txx9_primary_pcic; + + register_pci_controller(c); + + if (__raw_readq(&tx4938_ccfgptr->ccfg) & TX4938_CCFG_PCI66) + txx9_pci_option = + (txx9_pci_option & ~TXX9_PCI_OPT_CLK_MASK) | + TXX9_PCI_OPT_CLK_66; /* already configured */ + + /* Reset PCI Bus */ + writeb(0, rbtx4938_pcireset_addr); + /* Reset PCIC */ + txx9_set64(&tx4938_ccfgptr->clkctr, TX4938_CLKCTR_PCIRST); + if ((txx9_pci_option & TXX9_PCI_OPT_CLK_MASK) == + TXX9_PCI_OPT_CLK_66) + tx4938_pciclk66_setup(); + mdelay(10); + /* clear PCIC reset */ + txx9_clear64(&tx4938_ccfgptr->clkctr, TX4938_CLKCTR_PCIRST); + writeb(1, rbtx4938_pcireset_addr); + iob(); + + tx4938_report_pciclk(); + tx4927_pcic_setup(tx4938_pcicptr, c, extarb); + if ((txx9_pci_option & TXX9_PCI_OPT_CLK_MASK) == + TXX9_PCI_OPT_CLK_AUTO && + txx9_pci66_check(c, 0, 0)) { + /* Reset PCI Bus */ + writeb(0, rbtx4938_pcireset_addr); + /* Reset PCIC */ + txx9_set64(&tx4938_ccfgptr->clkctr, TX4938_CLKCTR_PCIRST); + tx4938_pciclk66_setup(); + mdelay(10); + /* clear PCIC reset */ + txx9_clear64(&tx4938_ccfgptr->clkctr, TX4938_CLKCTR_PCIRST); + writeb(1, rbtx4938_pcireset_addr); + iob(); + /* Reinitialize PCIC */ + tx4938_report_pciclk(); + tx4927_pcic_setup(tx4938_pcicptr, c, extarb); + } + + if (__raw_readq(&tx4938_ccfgptr->pcfg) & + (TX4938_PCFG_ETH0_SEL|TX4938_PCFG_ETH1_SEL)) { + /* Reset PCIC1 */ + txx9_set64(&tx4938_ccfgptr->clkctr, TX4938_CLKCTR_PCIC1RST); + /* PCI1DMD==0 => PCI1CLK==GBUSCLK/2 => PCI66 */ + if (!(__raw_readq(&tx4938_ccfgptr->ccfg) + & TX4938_CCFG_PCI1DMD)) + tx4938_ccfg_set(TX4938_CCFG_PCI1_66); + mdelay(10); + /* clear PCIC1 reset */ + txx9_clear64(&tx4938_ccfgptr->clkctr, TX4938_CLKCTR_PCIC1RST); + tx4938_report_pci1clk(); + + /* mem:64K(max), io:64K(max) (enough for ETH0,ETH1) */ + c = txx9_alloc_pci_controller(NULL, 0, 0x10000, 0, 0x10000); + register_pci_controller(c); + tx4927_pcic_setup(tx4938_pcic1ptr, c, 0); + } +#endif /* CONFIG_PCI */ +} + +/* SPI support */ + +/* chip select for SPI devices */ +#define SEEPROM1_CS 7 /* PIO7 */ +#define SEEPROM2_CS 0 /* IOC */ +#define SEEPROM3_CS 1 /* IOC */ +#define SRTC_CS 2 /* IOC */ + +static int __init rbtx4938_ethaddr_init(void) +{ +#ifdef CONFIG_PCI + unsigned char dat[17]; + unsigned char sum; + int i; + + /* 0-3: "MAC\0", 4-9:eth0, 10-15:eth1, 16:sum */ + if (spi_eeprom_read(SEEPROM1_CS, 0, dat, sizeof(dat))) { + printk(KERN_ERR "seeprom: read error.\n"); + return -ENODEV; + } else { + if (strcmp(dat, "MAC") != 0) + printk(KERN_WARNING "seeprom: bad signature.\n"); + for (i = 0, sum = 0; i < sizeof(dat); i++) + sum += dat[i]; + if (sum) + printk(KERN_WARNING "seeprom: bad checksum.\n"); + } + for (i = 0; i < 2; i++) { + unsigned int id = + TXX9_IRQ_BASE + (i ? TX4938_IR_ETH1 : TX4938_IR_ETH0); + struct platform_device *pdev; + if (!(__raw_readq(&tx4938_ccfgptr->pcfg) & + (i ? TX4938_PCFG_ETH1_SEL : TX4938_PCFG_ETH0_SEL))) + continue; + pdev = platform_device_alloc("tc35815-mac", id); + if (!pdev || + platform_device_add_data(pdev, &dat[4 + 6 * i], 6) || + platform_device_add(pdev)) + platform_device_put(pdev); + } +#endif /* CONFIG_PCI */ + return 0; +} + +static void __init rbtx4938_spi_setup(void) +{ + /* set SPI_SEL */ + txx9_set64(&tx4938_ccfgptr->pcfg, TX4938_PCFG_SPI_SEL); +} + +static struct resource rbtx4938_fpga_resource; + +static void __init rbtx4938_time_init(void) +{ + tx4938_time_init(0); +} + +static void __init rbtx4938_mem_setup(void) +{ + unsigned long long pcfg; + char *argptr; + + if (txx9_master_clock == 0) + txx9_master_clock = 25000000; /* 25MHz */ + + tx4938_setup(); + +#ifdef CONFIG_PCI + txx9_alloc_pci_controller(&txx9_primary_pcic, 0, 0, 0, 0); +#else + set_io_port_base(RBTX4938_ETHER_BASE); +#endif + + tx4938_setup_serial(); +#ifdef CONFIG_SERIAL_TXX9_CONSOLE + argptr = prom_getcmdline(); + if (strstr(argptr, "console=") == NULL) { + strcat(argptr, " console=ttyS0,38400"); + } +#endif + +#ifdef CONFIG_TOSHIBA_RBTX4938_MPLEX_PIO58_61 + printk("PIOSEL: disabling both ata and nand selection\n"); + local_irq_disable(); + txx9_clear64(&tx4938_ccfgptr->pcfg, + TX4938_PCFG_NDF_SEL | TX4938_PCFG_ATA_SEL); +#endif + +#ifdef CONFIG_TOSHIBA_RBTX4938_MPLEX_NAND + printk("PIOSEL: enabling nand selection\n"); + txx9_set64(&tx4938_ccfgptr->pcfg, TX4938_PCFG_NDF_SEL); + txx9_clear64(&tx4938_ccfgptr->pcfg, TX4938_PCFG_ATA_SEL); +#endif + +#ifdef CONFIG_TOSHIBA_RBTX4938_MPLEX_ATA + printk("PIOSEL: enabling ata selection\n"); + txx9_set64(&tx4938_ccfgptr->pcfg, TX4938_PCFG_ATA_SEL); + txx9_clear64(&tx4938_ccfgptr->pcfg, TX4938_PCFG_NDF_SEL); +#endif + +#ifdef CONFIG_IP_PNP + argptr = prom_getcmdline(); + if (strstr(argptr, "ip=") == NULL) { + strcat(argptr, " ip=any"); + } +#endif + + +#ifdef CONFIG_FB + { + conswitchp = &dummy_con; + } +#endif + + rbtx4938_spi_setup(); + pcfg = ____raw_readq(&tx4938_ccfgptr->pcfg); /* updated */ + /* fixup piosel */ + if ((pcfg & (TX4938_PCFG_ATA_SEL | TX4938_PCFG_NDF_SEL)) == + TX4938_PCFG_ATA_SEL) + writeb((readb(rbtx4938_piosel_addr) & 0x03) | 0x04, + rbtx4938_piosel_addr); + else if ((pcfg & (TX4938_PCFG_ATA_SEL | TX4938_PCFG_NDF_SEL)) == + TX4938_PCFG_NDF_SEL) + writeb((readb(rbtx4938_piosel_addr) & 0x03) | 0x08, + rbtx4938_piosel_addr); + else + writeb(readb(rbtx4938_piosel_addr) & ~(0x08 | 0x04), + rbtx4938_piosel_addr); + + rbtx4938_fpga_resource.name = "FPGA Registers"; + rbtx4938_fpga_resource.start = CPHYSADDR(RBTX4938_FPGA_REG_ADDR); + rbtx4938_fpga_resource.end = CPHYSADDR(RBTX4938_FPGA_REG_ADDR) + 0xffff; + rbtx4938_fpga_resource.flags = IORESOURCE_MEM | IORESOURCE_BUSY; + if (request_resource(&txx9_ce_res[2], &rbtx4938_fpga_resource)) + printk("request resource for fpga failed\n"); + + _machine_restart = rbtx4938_machine_restart; + _machine_halt = rbtx4938_machine_halt; + pm_power_off = rbtx4938_machine_power_off; + + writeb(0xff, rbtx4938_led_addr); + printk(KERN_INFO "RBTX4938 --- FPGA(Rev %02x) DIPSW:%02x,%02x\n", + readb(rbtx4938_fpga_rev_addr), + readb(rbtx4938_dipsw_addr), readb(rbtx4938_bdipsw_addr)); +} + +static int __init rbtx4938_ne_init(void) +{ + struct resource res[] = { + { + .start = RBTX4938_RTL_8019_BASE, + .end = RBTX4938_RTL_8019_BASE + 0x20 - 1, + .flags = IORESOURCE_IO, + }, { + .start = RBTX4938_RTL_8019_IRQ, + .flags = IORESOURCE_IRQ, + } + }; + struct platform_device *dev = + platform_device_register_simple("ne", -1, + res, ARRAY_SIZE(res)); + return IS_ERR(dev) ? PTR_ERR(dev) : 0; +} + +static DEFINE_SPINLOCK(rbtx4938_spi_gpio_lock); + +static void rbtx4938_spi_gpio_set(struct gpio_chip *chip, unsigned int offset, + int value) +{ + u8 val; + unsigned long flags; + spin_lock_irqsave(&rbtx4938_spi_gpio_lock, flags); + val = readb(rbtx4938_spics_addr); + if (value) + val |= 1 << offset; + else + val &= ~(1 << offset); + writeb(val, rbtx4938_spics_addr); + mmiowb(); + spin_unlock_irqrestore(&rbtx4938_spi_gpio_lock, flags); +} + +static int rbtx4938_spi_gpio_dir_out(struct gpio_chip *chip, + unsigned int offset, int value) +{ + rbtx4938_spi_gpio_set(chip, offset, value); + return 0; +} + +static struct gpio_chip rbtx4938_spi_gpio_chip = { + .set = rbtx4938_spi_gpio_set, + .direction_output = rbtx4938_spi_gpio_dir_out, + .label = "RBTX4938-SPICS", + .base = 16, + .ngpio = 3, +}; + +/* SPI support */ + +static void __init txx9_spi_init(unsigned long base, int irq) +{ + struct resource res[] = { + { + .start = base, + .end = base + 0x20 - 1, + .flags = IORESOURCE_MEM, + }, { + .start = irq, + .flags = IORESOURCE_IRQ, + }, + }; + platform_device_register_simple("spi_txx9", 0, + res, ARRAY_SIZE(res)); +} + +static int __init rbtx4938_spi_init(void) +{ + struct spi_board_info srtc_info = { + .modalias = "rtc-rs5c348", + .max_speed_hz = 1000000, /* 1.0Mbps @ Vdd 2.0V */ + .bus_num = 0, + .chip_select = 16 + SRTC_CS, + /* Mode 1 (High-Active, Shift-Then-Sample), High Avtive CS */ + .mode = SPI_MODE_1 | SPI_CS_HIGH, + }; + spi_register_board_info(&srtc_info, 1); + spi_eeprom_register(SEEPROM1_CS); + spi_eeprom_register(16 + SEEPROM2_CS); + spi_eeprom_register(16 + SEEPROM3_CS); + gpio_request(16 + SRTC_CS, "rtc-rs5c348"); + gpio_direction_output(16 + SRTC_CS, 0); + gpio_request(SEEPROM1_CS, "seeprom1"); + gpio_direction_output(SEEPROM1_CS, 1); + gpio_request(16 + SEEPROM2_CS, "seeprom2"); + gpio_direction_output(16 + SEEPROM2_CS, 1); + gpio_request(16 + SEEPROM3_CS, "seeprom3"); + gpio_direction_output(16 + SEEPROM3_CS, 1); + txx9_spi_init(TX4938_SPI_REG & 0xfffffffffULL, RBTX4938_IRQ_IRC_SPI); + return 0; +} + +static void __init rbtx4938_arch_init(void) +{ + gpiochip_add(&rbtx4938_spi_gpio_chip); + rbtx4938_pci_setup(); + rbtx4938_spi_init(); +} + +/* Watchdog support */ + +static int __init txx9_wdt_init(unsigned long base) +{ + struct resource res = { + .start = base, + .end = base + 0x100 - 1, + .flags = IORESOURCE_MEM, + }; + struct platform_device *dev = + platform_device_register_simple("txx9wdt", -1, &res, 1); + return IS_ERR(dev) ? PTR_ERR(dev) : 0; +} + +static int __init rbtx4938_wdt_init(void) +{ + return txx9_wdt_init(TX4938_TMR_REG(2) & 0xfffffffffULL); +} + +static void __init rbtx4938_device_init(void) +{ + rbtx4938_ethaddr_init(); + rbtx4938_ne_init(); + rbtx4938_wdt_init(); +} + +struct txx9_board_vec rbtx4938_vec __initdata = { + .system = "Toshiba RBTX4938", + .prom_init = rbtx4938_prom_init, + .mem_setup = rbtx4938_mem_setup, + .irq_setup = rbtx4938_irq_setup, + .time_init = rbtx4938_time_init, + .device_init = rbtx4938_device_init, + .arch_init = rbtx4938_arch_init, +#ifdef CONFIG_PCI + .pci_map_irq = rbtx4938_pci_map_irq, +#endif +}; diff --git a/arch/mips/txx9/rbtx4938/spi_eeprom.c b/arch/mips/txx9/rbtx4938/spi_eeprom.c new file mode 100644 index 00000000000..a7ea8b041c1 --- /dev/null +++ b/arch/mips/txx9/rbtx4938/spi_eeprom.c @@ -0,0 +1,99 @@ +/* + * spi_eeprom.c + * 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/device.h> +#include <linux/spi/spi.h> +#include <linux/spi/eeprom.h> +#include <asm/txx9/spi.h> + +#define AT250X0_PAGE_SIZE 8 + +/* register board information for at25 driver */ +int __init spi_eeprom_register(int chipid) +{ + static struct spi_eeprom eeprom = { + .name = "at250x0", + .byte_len = 128, + .page_size = AT250X0_PAGE_SIZE, + .flags = EE_ADDR1, + }; + struct spi_board_info info = { + .modalias = "at25", + .max_speed_hz = 1500000, /* 1.5Mbps */ + .bus_num = 0, + .chip_select = chipid, + .platform_data = &eeprom, + /* Mode 0: High-Active, Sample-Then-Shift */ + }; + + return spi_register_board_info(&info, 1); +} + +/* simple temporary spi driver to provide early access to seeprom. */ + +static struct read_param { + int chipid; + int address; + unsigned char *buf; + int len; +} *read_param; + +static int __init early_seeprom_probe(struct spi_device *spi) +{ + int stat = 0; + u8 cmd[2]; + int len = read_param->len; + char *buf = read_param->buf; + int address = read_param->address; + + dev_info(&spi->dev, "spiclk %u KHz.\n", + (spi->max_speed_hz + 500) / 1000); + if (read_param->chipid != spi->chip_select) + return -ENODEV; + while (len > 0) { + /* spi_write_then_read can only work with small chunk */ + int c = len < AT250X0_PAGE_SIZE ? len : AT250X0_PAGE_SIZE; + cmd[0] = 0x03; /* AT25_READ */ + cmd[1] = address; + stat = spi_write_then_read(spi, cmd, sizeof(cmd), buf, c); + buf += c; + len -= c; + address += c; + } + return stat; +} + +static struct spi_driver early_seeprom_driver __initdata = { + .driver = { + .name = "at25", + .owner = THIS_MODULE, + }, + .probe = early_seeprom_probe, +}; + +int __init spi_eeprom_read(int chipid, int address, + unsigned char *buf, int len) +{ + int ret; + struct read_param param = { + .chipid = chipid, + .address = address, + .buf = buf, + .len = len + }; + + read_param = ¶m; + ret = spi_register_driver(&early_seeprom_driver); + if (!ret) + spi_unregister_driver(&early_seeprom_driver); + return ret; +} |