diff options
Diffstat (limited to 'arch/mips/jmr3927')
-rw-r--r-- | arch/mips/jmr3927/common/Makefile | 5 | ||||
-rw-r--r-- | arch/mips/jmr3927/common/prom.c | 81 | ||||
-rw-r--r-- | arch/mips/jmr3927/common/puts.c | 168 | ||||
-rw-r--r-- | arch/mips/jmr3927/common/rtc_ds1742.c | 165 | ||||
-rw-r--r-- | arch/mips/jmr3927/rbhma3100/Makefile | 9 | ||||
-rw-r--r-- | arch/mips/jmr3927/rbhma3100/init.c | 77 | ||||
-rw-r--r-- | arch/mips/jmr3927/rbhma3100/int-handler.S | 74 | ||||
-rw-r--r-- | arch/mips/jmr3927/rbhma3100/irq.c | 466 | ||||
-rw-r--r-- | arch/mips/jmr3927/rbhma3100/kgdb_io.c | 155 | ||||
-rw-r--r-- | arch/mips/jmr3927/rbhma3100/setup.c | 510 |
10 files changed, 1710 insertions, 0 deletions
diff --git a/arch/mips/jmr3927/common/Makefile b/arch/mips/jmr3927/common/Makefile new file mode 100644 index 000000000000..cb09a8eede15 --- /dev/null +++ b/arch/mips/jmr3927/common/Makefile @@ -0,0 +1,5 @@ +# +# Makefile for the common code of TOSHIBA JMR-TX3927 board +# + +obj-y += prom.o puts.o rtc_ds1742.o diff --git a/arch/mips/jmr3927/common/prom.c b/arch/mips/jmr3927/common/prom.c new file mode 100644 index 000000000000..5d5838f41d23 --- /dev/null +++ b/arch/mips/jmr3927/common/prom.c @@ -0,0 +1,81 @@ +/* + * 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/kernel.h> +#include <linux/init.h> +#include <linux/string.h> + +#include <asm/bootinfo.h> + +extern int prom_argc; +extern char **prom_argv, **prom_envp; + +typedef struct +{ + char *name; +/* char *val; */ +}t_env_var; + + +char * __init prom_getcmdline(void) +{ + return &(arcs_cmdline[0]); +} + +void __init prom_init_cmdline(void) +{ + char *cp; + int actr; + + actr = 1; /* Always ignore argv[0] */ + + cp = &(arcs_cmdline[0]); + while(actr < prom_argc) { + strcpy(cp, prom_argv[actr]); + cp += strlen(prom_argv[actr]); + *cp++ = ' '; + actr++; + } + if (cp != &(arcs_cmdline[0])) /* get rid of trailing space */ + --cp; + *cp = '\0'; +} + +unsigned long __init prom_free_prom_memory(void) +{ + return 0; +} diff --git a/arch/mips/jmr3927/common/puts.c b/arch/mips/jmr3927/common/puts.c new file mode 100644 index 000000000000..1c1cad9cd078 --- /dev/null +++ b/arch/mips/jmr3927/common/puts.c @@ -0,0 +1,168 @@ +/* + * + * 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 + * + * Copyright (C) 2000-2001 Toshiba Corporation + * + * Based on arch/mips/au1000/common/puts.c + * + * 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/types.h> +#include <asm/jmr3927/txx927.h> +#include <asm/jmr3927/tx3927.h> +#include <asm/jmr3927/jmr3927.h> + +#define TIMEOUT 0xffffff +#define SLOW_DOWN + +static const char digits[16] = "0123456789abcdef"; + +#ifdef SLOW_DOWN +#define slow_down() { int k; for (k=0; k<10000; k++); } +#else +#define slow_down() +#endif + +void +putch(const unsigned char c) +{ + int i = 0; + + do { + slow_down(); + i++; + if (i>TIMEOUT) { + break; + } + } while (!(tx3927_sioptr(1)->cisr & TXx927_SICISR_TXALS)); + tx3927_sioptr(1)->tfifo = c; + return; +} + +unsigned char getch(void) +{ + int i = 0; + int dicr; + char c; + + /* diable RX int. */ + dicr = tx3927_sioptr(1)->dicr; + tx3927_sioptr(1)->dicr = 0; + + do { + slow_down(); + i++; + if (i>TIMEOUT) { + break; + } + } while (tx3927_sioptr(1)->disr & TXx927_SIDISR_UVALID) + ; + c = tx3927_sioptr(1)->rfifo; + + /* clear RX int. status */ + tx3927_sioptr(1)->disr &= ~TXx927_SIDISR_RDIS; + /* enable RX int. */ + tx3927_sioptr(1)->dicr = dicr; + + return c; +} +void +do_jmr3927_led_set(char n) +{ + /* and with current leds */ + jmr3927_led_and_set(n); +} + +void +puts(unsigned char *cp) +{ + int i = 0; + + while (*cp) { + do { + slow_down(); + i++; + if (i>TIMEOUT) { + break; + } + } while (!(tx3927_sioptr(1)->cisr & TXx927_SICISR_TXALS)); + tx3927_sioptr(1)->tfifo = *cp++; + } + putch('\r'); + putch('\n'); +} + +void +fputs(unsigned char *cp) +{ + int i = 0; + + while (*cp) { + do { + slow_down(); + i++; + if (i>TIMEOUT) { + break; + } + } while (!(tx3927_sioptr(1)->cisr & TXx927_SICISR_TXALS)); + tx3927_sioptr(1)->tfifo = *cp++; + } +} + + +void +put64(uint64_t ul) +{ + int cnt; + unsigned ch; + + cnt = 16; /* 16 nibbles in a 64 bit long */ + putch('0'); + putch('x'); + do { + cnt--; + ch = (unsigned char)(ul >> cnt * 4) & 0x0F; + putch(digits[ch]); + } while (cnt > 0); +} + +void +put32(unsigned u) +{ + int cnt; + unsigned ch; + + cnt = 8; /* 8 nibbles in a 32 bit long */ + putch('0'); + putch('x'); + do { + cnt--; + ch = (unsigned char)(u >> cnt * 4) & 0x0F; + putch(digits[ch]); + } while (cnt > 0); +} diff --git a/arch/mips/jmr3927/common/rtc_ds1742.c b/arch/mips/jmr3927/common/rtc_ds1742.c new file mode 100644 index 000000000000..1ae4318e1358 --- /dev/null +++ b/arch/mips/jmr3927/common/rtc_ds1742.c @@ -0,0 +1,165 @@ +/* + * Copyright 2001 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * ahennessy@mvista.com + * + * arch/mips/jmr3927/common/rtc_ds1742.c + * Based on arch/mips/ddb5xxx/common/rtc_ds1386.c + * low-level RTC hookups for s for Dallas 1742 chip. + * + * 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. + */ + + +/* + * This file exports a function, rtc_ds1386_init(), which expects an + * uncached base address as the argument. It will set the two function + * pointers expected by the MIPS generic timer code. + */ + +#include <linux/bcd.h> +#include <linux/types.h> +#include <linux/time.h> +#include <linux/rtc.h> + +#include <asm/time.h> +#include <asm/addrspace.h> + +#include <asm/jmr3927/ds1742rtc.h> +#include <asm/debug.h> + +#define EPOCH 2000 + +static unsigned long rtc_base; + +static unsigned long +rtc_ds1742_get_time(void) +{ + unsigned int year, month, day, hour, minute, second; + unsigned int century; + + CMOS_WRITE(RTC_READ, RTC_CONTROL); + second = BCD2BIN(CMOS_READ(RTC_SECONDS) & RTC_SECONDS_MASK); + minute = BCD2BIN(CMOS_READ(RTC_MINUTES)); + hour = BCD2BIN(CMOS_READ(RTC_HOURS)); + day = BCD2BIN(CMOS_READ(RTC_DATE)); + month = BCD2BIN(CMOS_READ(RTC_MONTH)); + year = BCD2BIN(CMOS_READ(RTC_YEAR)); + century = BCD2BIN(CMOS_READ(RTC_CENTURY) & RTC_CENTURY_MASK); + CMOS_WRITE(0, RTC_CONTROL); + + year += century * 100; + + return mktime(year, month, day, hour, minute, second); +} +extern void to_tm(unsigned long tim, struct rtc_time * tm); + +static int +rtc_ds1742_set_time(unsigned long t) +{ + struct rtc_time tm; + u8 year, month, day, hour, minute, second; + u8 cmos_year, cmos_month, cmos_day, cmos_hour, cmos_minute, cmos_second; + int cmos_century; + + CMOS_WRITE(RTC_READ, RTC_CONTROL); + cmos_second = (u8)(CMOS_READ(RTC_SECONDS) & RTC_SECONDS_MASK); + cmos_minute = (u8)CMOS_READ(RTC_MINUTES); + cmos_hour = (u8)CMOS_READ(RTC_HOURS); + cmos_day = (u8)CMOS_READ(RTC_DATE); + cmos_month = (u8)CMOS_READ(RTC_MONTH); + cmos_year = (u8)CMOS_READ(RTC_YEAR); + cmos_century = CMOS_READ(RTC_CENTURY) & RTC_CENTURY_MASK; + + CMOS_WRITE(RTC_WRITE, RTC_CONTROL); + + /* convert */ + to_tm(t, &tm); + + /* check each field one by one */ + year = BIN2BCD(tm.tm_year - EPOCH); + if (year != cmos_year) { + CMOS_WRITE(year,RTC_YEAR); + } + + month = BIN2BCD(tm.tm_mon); + if (month != (cmos_month & 0x1f)) { + CMOS_WRITE((month & 0x1f) | (cmos_month & ~0x1f),RTC_MONTH); + } + + day = BIN2BCD(tm.tm_mday); + if (day != cmos_day) { + + CMOS_WRITE(day, RTC_DATE); + } + + if (cmos_hour & 0x40) { + /* 12 hour format */ + hour = 0x40; + if (tm.tm_hour > 12) { + hour |= 0x20 | (BIN2BCD(hour-12) & 0x1f); + } else { + hour |= BIN2BCD(tm.tm_hour); + } + } else { + /* 24 hour format */ + hour = BIN2BCD(tm.tm_hour) & 0x3f; + } + if (hour != cmos_hour) CMOS_WRITE(hour, RTC_HOURS); + + minute = BIN2BCD(tm.tm_min); + if (minute != cmos_minute) { + CMOS_WRITE(minute, RTC_MINUTES); + } + + second = BIN2BCD(tm.tm_sec); + if (second != cmos_second) { + CMOS_WRITE(second & RTC_SECONDS_MASK,RTC_SECONDS); + } + + /* RTC_CENTURY and RTC_CONTROL share same address... */ + CMOS_WRITE(cmos_century, RTC_CONTROL); + + return 0; +} + +void +rtc_ds1742_init(unsigned long base) +{ + u8 cmos_second; + + /* remember the base */ + rtc_base = base; + db_assert((rtc_base & 0xe0000000) == KSEG1); + + /* set the function pointers */ + rtc_get_time = rtc_ds1742_get_time; + rtc_set_time = rtc_ds1742_set_time; + + /* clear oscillator stop bit */ + CMOS_WRITE(RTC_READ, RTC_CONTROL); + cmos_second = (u8)(CMOS_READ(RTC_SECONDS) & RTC_SECONDS_MASK); + CMOS_WRITE(RTC_WRITE, RTC_CONTROL); + CMOS_WRITE(cmos_second, RTC_SECONDS); /* clear msb */ + CMOS_WRITE(0, RTC_CONTROL); +} diff --git a/arch/mips/jmr3927/rbhma3100/Makefile b/arch/mips/jmr3927/rbhma3100/Makefile new file mode 100644 index 000000000000..75bf418b94c0 --- /dev/null +++ b/arch/mips/jmr3927/rbhma3100/Makefile @@ -0,0 +1,9 @@ +# +# Makefile for TOSHIBA JMR-TX3927 board +# + +obj-y += init.o int-handler.o irq.o setup.o +obj-$(CONFIG_RUNTIME_DEBUG) += debug.o +obj-$(CONFIG_KGDB) += kgdb_io.o + +EXTRA_AFLAGS := $(CFLAGS) diff --git a/arch/mips/jmr3927/rbhma3100/init.c b/arch/mips/jmr3927/rbhma3100/init.c new file mode 100644 index 000000000000..a0674d73962f --- /dev/null +++ b/arch/mips/jmr3927/rbhma3100/init.c @@ -0,0 +1,77 @@ +/* + * Copyright 2001 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * ahennessy@mvista.com + * + * arch/mips/jmr3927/common/init.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 <linux/config.h> +#include <linux/init.h> +#include <linux/mm.h> +#include <linux/sched.h> +#include <linux/bootmem.h> + +#include <asm/addrspace.h> +#include <asm/bootinfo.h> +#include <asm/mipsregs.h> +#include <asm/jmr3927/jmr3927.h> + +int prom_argc; +char **prom_argv, **prom_envp; +extern void __init prom_init_cmdline(void); +extern char *prom_getenv(char *envname); +unsigned long mips_nofpu = 0; + +const char *get_system_type(void) +{ + return "Toshiba" +#ifdef CONFIG_TOSHIBA_JMR3927 + " JMR_TX3927" +#endif + ; +} + +extern void puts(unsigned char *cp); + +void __init prom_init(void) +{ +#ifdef CONFIG_TOSHIBA_JMR3927 + /* CCFG */ + if ((tx3927_ccfgptr->ccfg & TX3927_CCFG_TLBOFF) == 0) + puts("Warning: TX3927 TLB off\n"); +#endif + prom_argc = fw_arg0; + prom_argv = (char **) fw_arg1; + prom_envp = (char **) fw_arg2; + + mips_machgroup = MACH_GROUP_TOSHIBA; + +#ifdef CONFIG_TOSHIBA_JMR3927 + mips_machtype = MACH_TOSHIBA_JMR3927; +#endif + + prom_init_cmdline(); + add_memory_region(0, JMR3927_SDRAM_SIZE, BOOT_MEM_RAM); +} diff --git a/arch/mips/jmr3927/rbhma3100/int-handler.S b/arch/mips/jmr3927/rbhma3100/int-handler.S new file mode 100644 index 000000000000..f85bbf407542 --- /dev/null +++ b/arch/mips/jmr3927/rbhma3100/int-handler.S @@ -0,0 +1,74 @@ +/* + * Copyright 2001 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * ahennessy@mvista.com + * + * Based on arch/mips/tsdb/kernel/int-handler.S + * + * 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/asm.h> +#include <asm/mipsregs.h> +#include <asm/regdef.h> +#include <asm/stackframe.h> +#include <asm/jmr3927/jmr3927.h> + + /* A lot of complication here is taken away because: + * + * 1) We handle one interrupt and return, sitting in a loop + * and moving across all the pending IRQ bits in the cause + * register is _NOT_ the answer, the common case is one + * pending IRQ so optimize in that direction. + * + * 2) We need not check against bits in the status register + * IRQ mask, that would make this routine slow as hell. + * + * 3) Linux only thinks in terms of all IRQs on or all IRQs + * off, nothing in between like BSD spl() brain-damage. + * + */ + +/* Flush write buffer (needed?) + * NOTE: TX39xx performs "non-blocking load", so explicitly use the target + * register of LBU to flush immediately. + */ +#define FLUSH_WB(tmp) \ + la tmp, JMR3927_IOC_REV_ADDR; \ + lbu tmp, (tmp); \ + move tmp, zero; + + .text + .set noreorder + .set noat + .align 5 + NESTED(jmr3927_IRQ, PT_SIZE, sp) + SAVE_ALL + CLI + .set at + jal jmr3927_irc_irqdispatch + move a0, sp + FLUSH_WB(t0) + j ret_from_irq + nop + END(jmr3927_IRQ) diff --git a/arch/mips/jmr3927/rbhma3100/irq.c b/arch/mips/jmr3927/rbhma3100/irq.c new file mode 100644 index 000000000000..b9799b86fc79 --- /dev/null +++ b/arch/mips/jmr3927/rbhma3100/irq.c @@ -0,0 +1,466 @@ +/* + * 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/config.h> +#include <linux/init.h> + +#include <linux/errno.h> +#include <linux/irq.h> +#include <linux/kernel_stat.h> +#include <linux/signal.h> +#include <linux/sched.h> +#include <linux/types.h> +#include <linux/interrupt.h> +#include <linux/ioport.h> +#include <linux/timex.h> +#include <linux/slab.h> +#include <linux/random.h> +#include <linux/smp.h> +#include <linux/smp_lock.h> +#include <linux/bitops.h> + +#include <asm/io.h> +#include <asm/mipsregs.h> +#include <asm/system.h> + +#include <asm/ptrace.h> +#include <asm/processor.h> +#include <asm/jmr3927/irq.h> +#include <asm/debug.h> +#include <asm/jmr3927/jmr3927.h> + +#if JMR3927_IRQ_END > NR_IRQS +#error JMR3927_IRQ_END > NR_IRQS +#endif + +struct tb_irq_space* tb_irq_spaces; + +static int jmr3927_irq_base = -1; + +#ifdef CONFIG_PCI +static int jmr3927_gen_iack(void) +{ + /* generate ACK cycle */ +#ifdef __BIG_ENDIAN + return (tx3927_pcicptr->iiadp >> 24) & 0xff; +#else + return tx3927_pcicptr->iiadp & 0xff; +#endif +} +#endif + +extern asmlinkage void jmr3927_IRQ(void); + +#define irc_dlevel 0 +#define irc_elevel 1 + +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 */ +}; + +static void jmr3927_irq_disable(unsigned int irq_nr); +static void jmr3927_irq_enable(unsigned int irq_nr); + +static DEFINE_SPINLOCK(jmr3927_irq_lock); + +static unsigned int jmr3927_irq_startup(unsigned int irq) +{ + jmr3927_irq_enable(irq); + + return 0; +} + +#define jmr3927_irq_shutdown jmr3927_irq_disable + +static void jmr3927_irq_ack(unsigned int irq) +{ + if (irq == JMR3927_IRQ_IRC_TMR0) + jmr3927_tmrptr->tisr = 0; /* ack interrupt */ + + jmr3927_irq_disable(irq); +} + +static void jmr3927_irq_end(unsigned int irq) +{ + jmr3927_irq_enable(irq); +} + +static void jmr3927_irq_disable(unsigned int irq_nr) +{ + struct tb_irq_space* sp; + unsigned long flags; + + spinlock_irqsave(&jmr3927_irq_lock, flags); + for (sp = tb_irq_spaces; sp; sp = sp->next) { + if (sp->start_irqno <= irq_nr && + irq_nr < sp->start_irqno + sp->nr_irqs) { + if (sp->mask_func) + sp->mask_func(irq_nr - sp->start_irqno, + sp->space_id); + break; + } + } + spinlock_irqrestore(&jmr3927_irq_lock, flags); +} + +static void jmr3927_irq_enable(unsigned int irq_nr) +{ + struct tb_irq_space* sp; + unsigned long flags; + + spinlock_irqsave(&jmr3927_irq_lock, flags); + for (sp = tb_irq_spaces; sp; sp = sp->next) { + if (sp->start_irqno <= irq_nr && + irq_nr < sp->start_irqno + sp->nr_irqs) { + if (sp->unmask_func) + sp->unmask_func(irq_nr - sp->start_irqno, + sp->space_id); + break; + } + } + spinlock_irqrestore(&jmr3927_irq_lock, flags); +} + +/* + * CP0_STATUS is a thread's resource (saved/restored on context switch). + * So disable_irq/enable_irq MUST handle IOC/ISAC/IRC registers. + */ +static void mask_irq_isac(int irq_nr, int space_id) +{ + /* 0: mask */ + unsigned char imask = + jmr3927_isac_reg_in(JMR3927_ISAC_INTM_ADDR); + unsigned int bit = 1 << irq_nr; + jmr3927_isac_reg_out(imask & ~bit, JMR3927_ISAC_INTM_ADDR); + /* flush write buffer */ + (void)jmr3927_ioc_reg_in(JMR3927_IOC_REV_ADDR); +} +static void unmask_irq_isac(int irq_nr, int space_id) +{ + /* 0: mask */ + unsigned char imask = jmr3927_isac_reg_in(JMR3927_ISAC_INTM_ADDR); + unsigned int bit = 1 << irq_nr; + jmr3927_isac_reg_out(imask | bit, JMR3927_ISAC_INTM_ADDR); + /* flush write buffer */ + (void)jmr3927_ioc_reg_in(JMR3927_IOC_REV_ADDR); +} + +static void mask_irq_ioc(int irq_nr, int space_id) +{ + /* 0: mask */ + 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(int irq_nr, int space_id) +{ + /* 0: mask */ + 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 mask_irq_irc(int irq_nr, int space_id) +{ + volatile unsigned long *ilrp = &tx3927_ircptr->ilr[irq_nr / 2]; + if (irq_nr & 1) + *ilrp = (*ilrp & 0x00ff) | (irc_dlevel << 8); + else + *ilrp = (*ilrp & 0xff00) | irc_dlevel; + /* update IRCSR */ + tx3927_ircptr->imr = 0; + tx3927_ircptr->imr = irc_elevel; +} +static void unmask_irq_irc(int irq_nr, int space_id) +{ + volatile unsigned long *ilrp = &tx3927_ircptr->ilr[irq_nr / 2]; + if (irq_nr & 1) + *ilrp = (*ilrp & 0x00ff) | (irc_level[irq_nr] << 8); + else + *ilrp = (*ilrp & 0xff00) | irc_level[irq_nr]; + /* update IRCSR */ + tx3927_ircptr->imr = 0; + tx3927_ircptr->imr = irc_elevel; +} + +struct tb_irq_space jmr3927_isac_irqspace = { + .next = NULL, + .start_irqno = JMR3927_IRQ_ISAC, + nr_irqs : JMR3927_NR_IRQ_ISAC, + .mask_func = mask_irq_isac, + .unmask_func = unmask_irq_isac, + .name = "ISAC", + .space_id = 0, + can_share : 0 +}; +struct tb_irq_space jmr3927_ioc_irqspace = { + .next = NULL, + .start_irqno = JMR3927_IRQ_IOC, + nr_irqs : JMR3927_NR_IRQ_IOC, + .mask_func = mask_irq_ioc, + .unmask_func = unmask_irq_ioc, + .name = "IOC", + .space_id = 0, + can_share : 1 +}; +struct tb_irq_space jmr3927_irc_irqspace = { + .next = NULL, + .start_irqno = JMR3927_IRQ_IRC, + nr_irqs : JMR3927_NR_IRQ_IRC, + .mask_func = mask_irq_irc, + .unmask_func = unmask_irq_irc, + .name = "on-chip", + .space_id = 0, + can_share : 0 +}; + +void jmr3927_spurious(struct pt_regs *regs) +{ +#ifdef CONFIG_TX_BRANCH_LIKELY_BUG_WORKAROUND + tx_branch_likely_bug_fixup(regs); +#endif + printk(KERN_WARNING "spurious interrupt (cause 0x%lx, pc 0x%lx, ra 0x%lx).\n", + regs->cp0_cause, regs->cp0_epc, regs->regs[31]); +} + +void jmr3927_irc_irqdispatch(struct pt_regs *regs) +{ + int irq; + +#ifdef CONFIG_TX_BRANCH_LIKELY_BUG_WORKAROUND + tx_branch_likely_bug_fixup(regs); +#endif + if ((regs->cp0_cause & CAUSEF_IP7) == 0) { +#if 0 + jmr3927_spurious(regs); +#endif + return; + } + irq = (regs->cp0_cause >> CAUSEB_IP2) & 0x0f; + + do_IRQ(irq + JMR3927_IRQ_IRC, regs); +} + +static void jmr3927_ioc_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + 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)) { + irq = JMR3927_IRQ_IOC + i; + do_IRQ(irq, regs); + } + } +} + +static struct irqaction ioc_action = { + jmr3927_ioc_interrupt, 0, CPU_MASK_NONE, "IOC", NULL, NULL, +}; + +static void jmr3927_isac_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + unsigned char istat = jmr3927_isac_reg_in(JMR3927_ISAC_INTS2_ADDR); + int i; + + for (i = 0; i < JMR3927_NR_IRQ_ISAC; i++) { + if (istat & (1 << i)) { + irq = JMR3927_IRQ_ISAC + i; + do_IRQ(irq, regs); + } + } +} + +static struct irqaction isac_action = { + jmr3927_isac_interrupt, 0, CPU_MASK_NONE, "ISAC", NULL, NULL, +}; + + +static void jmr3927_isaerr_interrupt(int irq, void * dev_id, struct pt_regs * regs) +{ + printk(KERN_WARNING "ISA error interrupt (irq 0x%x).\n", irq); +} +static struct irqaction isaerr_action = { + jmr3927_isaerr_interrupt, 0, CPU_MASK_NONE, "ISA error", NULL, NULL, +}; + +static void jmr3927_pcierr_interrupt(int irq, void * dev_id, struct pt_regs * regs) +{ + 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); +} +static struct irqaction pcierr_action = { + jmr3927_pcierr_interrupt, 0, CPU_MASK_NONE, "PCI error", NULL, NULL, +}; + +int jmr3927_ether1_irq = 0; + +void jmr3927_irq_init(u32 irq_base); + +void __init arch_init_irq(void) +{ + /* look for io board's presence */ + int have_isac = jmr3927_have_isac(); + + /* Now, interrupt control disabled, */ + /* all IRC interrupts are masked, */ + /* all IRC interrupt mode are Low Active. */ + + if (have_isac) { + + /* ETHER1 (NE2000 compatible 10M-Ether) parameter setup */ + /* temporary enable interrupt control */ + tx3927_ircptr->cer = 1; + /* ETHER1 Int. Is High-Active. */ + if (tx3927_ircptr->ssr & (1 << 0)) + jmr3927_ether1_irq = JMR3927_IRQ_IRC_INT0; +#if 0 /* INT3 may be asserted by ether0 (even after reboot...) */ + else if (tx3927_ircptr->ssr & (1 << 3)) + jmr3927_ether1_irq = JMR3927_IRQ_IRC_INT3; +#endif + /* disable interrupt control */ + tx3927_ircptr->cer = 0; + + /* Ether1: High Active */ + if (jmr3927_ether1_irq) { + int ether1_irc = jmr3927_ether1_irq - JMR3927_IRQ_IRC; + tx3927_ircptr->cr[ether1_irc / 8] |= + TX3927_IRCR_HIGH << ((ether1_irc % 8) * 2); + } + } + + /* 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); + + if (have_isac) { + /* mask all ISAC interrupts */ + jmr3927_isac_reg_out(0, JMR3927_ISAC_INTM_ADDR); + /* setup ISAC interrupt mode (ISAIRQ3,ISAIRQ5:Low Active ???) */ + jmr3927_isac_reg_out(JMR3927_ISAC_INTF_IRQ3|JMR3927_ISAC_INTF_IRQ5, JMR3927_ISAC_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); + + /* enable interrupt control */ + tx3927_ircptr->cer = TX3927_IRCER_ICE; + tx3927_ircptr->imr = irc_elevel; + + jmr3927_irq_init(NR_ISA_IRQS); + + set_except_vector(0, jmr3927_IRQ); + + /* setup irq space */ + add_tb_irq_space(&jmr3927_isac_irqspace); + add_tb_irq_space(&jmr3927_ioc_irqspace); + add_tb_irq_space(&jmr3927_irc_irqspace); + + /* setup IOC interrupt 1 (PCI, MODEM) */ + setup_irq(JMR3927_IRQ_IOCINT, &ioc_action); + + if (have_isac) { + setup_irq(JMR3927_IRQ_ISACINT, &isac_action); + setup_irq(JMR3927_IRQ_ISAC_ISAER, &isaerr_action); + } + +#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 hw_irq_controller jmr3927_irq_controller = { + "jmr3927_irq", + jmr3927_irq_startup, + jmr3927_irq_shutdown, + jmr3927_irq_enable, + jmr3927_irq_disable, + jmr3927_irq_ack, + jmr3927_irq_end, +}; + +void jmr3927_irq_init(u32 irq_base) +{ + u32 i; + + for (i= irq_base; i< irq_base + JMR3927_NR_IRQ_IRC + JMR3927_NR_IRQ_IOC; i++) { + irq_desc[i].status = IRQ_DISABLED; + irq_desc[i].action = NULL; + irq_desc[i].depth = 1; + irq_desc[i].handler = &jmr3927_irq_controller; + } + + jmr3927_irq_base = irq_base; +} + +#ifdef CONFIG_TX_BRANCH_LIKELY_BUG_WORKAROUND +static int tx_branch_likely_bug_count = 0; +static int have_tx_branch_likely_bug = 0; +void tx_branch_likely_bug_fixup(struct pt_regs *regs) +{ + /* TX39/49-BUG: Under this condition, the insn in delay slot + of the branch likely insn is executed (not nullified) even + the branch condition is false. */ + if (!have_tx_branch_likely_bug) + return; + if ((regs->cp0_epc & 0xfff) == 0xffc && + KSEGX(regs->cp0_epc) != KSEG0 && + KSEGX(regs->cp0_epc) != KSEG1) { + unsigned int insn = *(unsigned int*)(regs->cp0_epc - 4); + /* beql,bnel,blezl,bgtzl */ + /* bltzl,bgezl,blezall,bgezall */ + /* bczfl, bcztl */ + if ((insn & 0xf0000000) == 0x50000000 || + (insn & 0xfc0e0000) == 0x04020000 || + (insn & 0xf3fe0000) == 0x41020000) { + regs->cp0_epc -= 4; + tx_branch_likely_bug_count++; + printk(KERN_INFO + "fix branch-likery bug in %s (insn %08x)\n", + current->comm, insn); + } + } +} +#endif diff --git a/arch/mips/jmr3927/rbhma3100/kgdb_io.c b/arch/mips/jmr3927/rbhma3100/kgdb_io.c new file mode 100644 index 000000000000..269a42deae06 --- /dev/null +++ b/arch/mips/jmr3927/rbhma3100/kgdb_io.c @@ -0,0 +1,155 @@ +/* + * 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 <linux/types.h> +#include <asm/jmr3927/txx927.h> +#include <asm/jmr3927/tx3927.h> +#include <asm/jmr3927/jmr3927.h> + +#define TIMEOUT 0xffffff +#define SLOW_DOWN + +static const char digits[16] = "0123456789abcdef"; + +#ifdef SLOW_DOWN +#define slow_down() { int k; for (k=0; k<10000; k++); } +#else +#define slow_down() +#endif + +static int remoteDebugInitialized = 0; + +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; +} + +void debugInit(int baud) +{ + /* + volatile unsigned long lcr; + volatile unsigned long dicr; + volatile unsigned long disr; + volatile unsigned long cisr; + volatile unsigned long fcr; + volatile unsigned long flcr; + volatile unsigned long bgr; + volatile unsigned long tfifo; + volatile unsigned long rfifo; + */ + + 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; +#if 0 + /* + * Reset the UART. + */ + tx3927_sioptr(0)->fcr = TXx927_SIFCR_SWRST; + while (tx3927_sioptr(0)->fcr & TXx927_SIFCR_SWRST) + ; + + /* + * and set the speed of the serial port + * (currently hardwired to 9600 8N1 + */ + + tx3927_sioptr(0)->lcr = TXx927_SILCR_UMODE_8BIT | + TXx927_SILCR_USBL_1BIT | + TXx927_SILCR_SCS_IMCLK_BG; + tx3927_sioptr(0)->bgr = + ((JMR3927_BASE_BAUD + baud / 2) / baud) | + TXx927_SIBGR_BCLK_T0; + + /* HW RTS/CTS control */ + if (ser->flags & ASYNC_HAVE_CTS_LINE) + tx3927_sioptr(0)->flcr = TXx927_SIFLCR_RCS | TXx927_SIFLCR_TES | + TXx927_SIFLCR_RTSTL_MAX /* 15 */; + /* Enable RX/TX */ + tx3927_sioptr(0)->flcr &= ~(TXx927_SIFLCR_RSDE | TXx927_SIFLCR_TSDE); +#endif +} diff --git a/arch/mips/jmr3927/rbhma3100/setup.c b/arch/mips/jmr3927/rbhma3100/setup.c new file mode 100644 index 000000000000..32039bb2f440 --- /dev/null +++ b/arch/mips/jmr3927/rbhma3100/setup.c @@ -0,0 +1,510 @@ +/*********************************************************************** + * + * Copyright 2001 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * ahennessy@mvista.com + * + * Based on arch/mips/ddb5xxx/ddb5477/setup.c + * + * Setup file for JMR3927. + * + * 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/config.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/kdev_t.h> +#include <linux/types.h> +#include <linux/sched.h> +#include <linux/pci.h> +#include <linux/ide.h> +#include <linux/ioport.h> +#include <linux/param.h> /* for HZ */ +#include <linux/delay.h> + +#include <asm/addrspace.h> +#include <asm/time.h> +#include <asm/bcache.h> +#include <asm/irq.h> +#include <asm/reboot.h> +#include <asm/gdb-stub.h> +#include <asm/jmr3927/jmr3927.h> +#include <asm/mipsregs.h> +#include <asm/traps.h> + +/* Tick Timer divider */ +#define JMR3927_TIMER_CCD 0 /* 1/2 */ +#define JMR3927_TIMER_CLK (JMR3927_IMCLK / (2 << JMR3927_TIMER_CCD)) + +unsigned char led_state = 0xf; + +struct { + struct resource ram0; + struct resource ram1; + struct resource pcimem; + struct resource iob; + struct resource ioc; + struct resource pciio; + struct resource jmy1394; + struct resource rom1; + struct resource rom0; + struct resource sio0; + struct resource sio1; +} jmr3927_resources = { + { "RAM0", 0, 0x01FFFFFF, IORESOURCE_MEM }, + { "RAM1", 0x02000000, 0x03FFFFFF, IORESOURCE_MEM }, + { "PCIMEM", 0x08000000, 0x07FFFFFF, IORESOURCE_MEM }, + { "IOB", 0x10000000, 0x13FFFFFF }, + { "IOC", 0x14000000, 0x14FFFFFF }, + { "PCIIO", 0x15000000, 0x15FFFFFF }, + { "JMY1394", 0x1D000000, 0x1D3FFFFF }, + { "ROM1", 0x1E000000, 0x1E3FFFFF }, + { "ROM0", 0x1FC00000, 0x1FFFFFFF }, + { "SIO0", 0xFFFEF300, 0xFFFEF3FF }, + { "SIO1", 0xFFFEF400, 0xFFFEF4FF }, +}; + +/* don't enable - see errata */ +int jmr3927_ccfg_toeon = 0; + +static inline void do_reset(void) +{ +#ifdef CONFIG_TC35815 + extern void tc35815_killall(void); + tc35815_killall(); +#endif +#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); +} + +#define USE_RTC_DS1742 +#ifdef USE_RTC_DS1742 +extern void rtc_ds1742_init(unsigned long base); +#endif +static void __init jmr3927_time_init(void) +{ +#ifdef USE_RTC_DS1742 + if (jmr3927_have_nvram()) { + rtc_ds1742_init(JMR3927_IOC_NVRAMB_ADDR); + } +#endif +} + +unsigned long jmr3927_do_gettimeoffset(void); +extern int setup_irq(unsigned int irq, struct irqaction *irqaction); + +static void __init jmr3927_timer_setup(struct irqaction *irq) +{ + do_gettimeoffset = jmr3927_do_gettimeoffset; + + jmr3927_tmrptr->cpra = JMR3927_TIMER_CLK / HZ; + jmr3927_tmrptr->itmr = TXx927_TMTITMR_TIIE | TXx927_TMTITMR_TZCE; + jmr3927_tmrptr->ccdr = JMR3927_TIMER_CCD; + jmr3927_tmrptr->tcr = + TXx927_TMTCR_TCE | TXx927_TMTCR_CCDE | TXx927_TMTCR_TMODE_ITVL; + + setup_irq(JMR3927_IRQ_TICK, irq); +} + +#define USECS_PER_JIFFY (1000000/HZ) + +unsigned long jmr3927_do_gettimeoffset(void) +{ + unsigned long count; + unsigned long res = 0; + + /* MUST read TRR before TISR. */ + count = jmr3927_tmrptr->trr; + + if (jmr3927_tmrptr->tisr & TXx927_TMTISR_TIIS) { + /* timer interrupt is pending. use Max value. */ + res = USECS_PER_JIFFY - 1; + } else { + /* convert to usec */ + /* res = count / (JMR3927_TIMER_CLK / 1000000); */ + res = (count << 7) / ((JMR3927_TIMER_CLK << 7) / 1000000); + + /* + * Due to possible jiffies inconsistencies, we need to check + * the result so that we'll get a timer that is monotonic. + */ + if (res >= USECS_PER_JIFFY) + res = USECS_PER_JIFFY-1; + } + + return res; +} + + +//#undef DO_WRITE_THROUGH +#define DO_WRITE_THROUGH +#define DO_ENABLE_CACHE + +extern char * __init prom_getcmdline(void); +static void jmr3927_board_init(void); +extern struct resource pci_io_resource; +extern struct resource pci_mem_resource; + +static void __init jmr3927_setup(void) +{ + char *argptr; + + set_io_port_base(JMR3927_PORT_BASE + JMR3927_PCIIO); + + board_time_init = jmr3927_time_init; + board_timer_setup = jmr3927_timer_setup; + + _machine_restart = jmr3927_machine_restart; + _machine_halt = jmr3927_machine_halt; + _machine_power_off = jmr3927_machine_power_off; + + /* + * IO/MEM resources. + */ + ioport_resource.start = pci_io_resource.start; + ioport_resource.end = pci_io_resource.end; + iomem_resource.start = pci_mem_resource.start; + iomem_resource.end = pci_mem_resource.end; + + /* Reboot on panic */ + panic_timeout = 180; + + { + unsigned int conf; + conf = read_c0_conf(); + } + +#if 1 + /* 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); + } +#endif + + /* 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_TXX927_SERIAL_CONSOLE + argptr = prom_getcmdline(); + if ((argptr = strstr(argptr, "console=")) == NULL) { + argptr = prom_getcmdline(); + strcat(argptr, " console=ttyS1,115200"); + } +#endif +} + +early_initcall(jmr3927_setup); + + +static void tx3927_setup(void); + +#ifdef CONFIG_PCI +unsigned long mips_pci_io_base; +unsigned long mips_pci_io_size; +unsigned long mips_pci_mem_base; +unsigned long mips_pci_mem_size; +/* for legacy I/O, PCI I/O PCI Bus address must be 0 */ +unsigned long mips_pci_io_pciaddr = 0; +#endif + +static void __init jmr3927_board_init(void) +{ + char *argptr; + +#ifdef CONFIG_PCI + mips_pci_io_base = JMR3927_PCIIO; + mips_pci_io_size = JMR3927_PCIIO_SIZE; + mips_pci_mem_base = JMR3927_PCIMEM; + mips_pci_mem_size = JMR3927_PCIMEM_SIZE; +#endif + + tx3927_setup(); + + if (jmr3927_have_isac()) { + +#ifdef CONFIG_FB_E1355 + argptr = prom_getcmdline(); + if ((argptr = strstr(argptr, "video=")) == NULL) { + argptr = prom_getcmdline(); + strcat(argptr, " video=e1355fb:crt16h"); + } +#endif + +#ifdef CONFIG_BLK_DEV_IDE + /* overrides PCI-IDE */ +#endif + } + + /* SIO0 DTR on */ + jmr3927_ioc_reg_out(0, JMR3927_IOC_DTR_ADDR); + + jmr3927_led_set(0); + + + if (jmr3927_have_isac()) + jmr3927_io_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()); + if (jmr3927_have_isac()) + printk("JMI-3927IO2 --- ISAC(Rev %d) DIPSW:%01x\n", + jmr3927_isac_reg_in(JMR3927_ISAC_REV_ADDR) & JMR3927_REV_MASK, + jmr3927_io_dipsw()); +} + +static void __init tx3927_setup(void) +{ + int i; + + /* 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; + +#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); + + /* IRC */ + /* disable interrupt control */ + tx3927_ircptr->cer = 0; + /* mask all IRC interrupts */ + tx3927_ircptr->imr = 0; + for (i = 0; i < TX3927_NUM_IR / 2; i++) { + tx3927_ircptr->ilr[i] = 0; + } + /* setup IRC interrupt mode (Low Active) */ + for (i = 0; i < TX3927_NUM_IR / 8; i++) { + tx3927_ircptr->cr[i] = 0; + } + + /* TMR */ + /* disable all timers */ + for (i = 0; i < TX3927_NR_TMR; i++) { + tx3927_tmrptr(i)->tcr = TXx927_TMTCR_CRE; + tx3927_tmrptr(i)->tisr = 0; + tx3927_tmrptr(i)->cpra = 0xffffffff; + tx3927_tmrptr(i)->itmr = 0; + tx3927_tmrptr(i)->ccdr = 0; + tx3927_tmrptr(i)->pgmr = 0; + } + + /* DMA */ + tx3927_dmaptr->mcr = 0; + for (i = 0; i < sizeof(tx3927_dmaptr->ch) / sizeof(tx3927_dmaptr->ch[0]); 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 + +#ifdef CONFIG_PCI + /* PCIC */ + printk("TX3927 PCIC -- DID:%04x VID:%04x RID:%02x Arbiter:", + tx3927_pcicptr->did, tx3927_pcicptr->vid, + tx3927_pcicptr->rid); + if (!(tx3927_ccfgptr->ccfg & TX3927_CCFG_PCIXARB)) { + printk("External\n"); + /* XXX */ + } else { + printk("Internal\n"); + + /* 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); + + + /* Disable External PCI Config. Access */ + tx3927_pcicptr->lbc = TX3927_PCIC_LBC_EPCAD; +#ifdef __BIG_ENDIAN + tx3927_pcicptr->lbc |= TX3927_PCIC_LBC_IBSE | + TX3927_PCIC_LBC_TIBSE | + TX3927_PCIC_LBC_TMFBSE | TX3927_PCIC_LBC_MSDSE; +#endif + /* LB->PCI mappings */ + tx3927_pcicptr->iomas = ~(mips_pci_io_size - 1); + tx3927_pcicptr->ilbioma = mips_pci_io_base; + tx3927_pcicptr->ipbioma = mips_pci_io_pciaddr; + tx3927_pcicptr->mmas = ~(mips_pci_mem_size - 1); + tx3927_pcicptr->ilbmma = mips_pci_mem_base; + tx3927_pcicptr->ipbmma = mips_pci_mem_base; + /* PCI->LB mappings */ + tx3927_pcicptr->iobas = 0xffffffff; + tx3927_pcicptr->ioba = 0; + tx3927_pcicptr->tlbioma = 0; + tx3927_pcicptr->mbas = ~(mips_pci_mem_size - 1); + tx3927_pcicptr->mba = 0; + tx3927_pcicptr->tlbmma = 0; +#ifndef JMR3927_INIT_INDIRECT_PCI + /* Enable Direct mapping Address Space Decoder */ + tx3927_pcicptr->lbc |= TX3927_PCIC_LBC_ILMDE | TX3927_PCIC_LBC_ILIDE; +#endif + + /* Clear All Local Bus Status */ + tx3927_pcicptr->lbstat = TX3927_PCIC_LBIM_ALL; + /* Enable All Local Bus Interrupts */ + tx3927_pcicptr->lbim = TX3927_PCIC_LBIM_ALL; + /* Clear All PCI Status Error */ + tx3927_pcicptr->pcistat = TX3927_PCIC_PCISTATIM_ALL; + /* Enable All PCI Status Error Interrupts */ + tx3927_pcicptr->pcistatim = TX3927_PCIC_PCISTATIM_ALL; + + /* PCIC Int => IRC IRQ10 */ + tx3927_pcicptr->il = TX3927_IR_PCI; +#if 1 + /* Target Control (per errata) */ + tx3927_pcicptr->tc = TX3927_PCIC_TC_OF8E | TX3927_PCIC_TC_IF8E; +#endif + + /* Enable Bus Arbiter */ +#if 0 + tx3927_pcicptr->req_trace = 0x73737373; +#endif + tx3927_pcicptr->pbapmc = TX3927_PCIC_PBAPMC_PBAEN; + + tx3927_pcicptr->pcicmd = PCI_COMMAND_MASTER | + PCI_COMMAND_MEMORY | +#if 1 + PCI_COMMAND_IO | +#endif + PCI_COMMAND_PARITY | PCI_COMMAND_SERR; + } +#endif /* CONFIG_PCI */ + + /* PIO */ + /* PIO[15:12] connected to LEDs */ + tx3927_pioptr->dir = 0x0000f000; + tx3927_pioptr->maskcpu = 0; + tx3927_pioptr->maskext = 0; + { + 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"); + } +} |