diff options
Diffstat (limited to 'arch/mips/mips-boards/generic')
-rw-r--r-- | arch/mips/mips-boards/generic/Makefile | 26 | ||||
-rw-r--r-- | arch/mips/mips-boards/generic/cmdline.c | 59 | ||||
-rw-r--r-- | arch/mips/mips-boards/generic/display.c | 39 | ||||
-rw-r--r-- | arch/mips/mips-boards/generic/gdb_hook.c | 133 | ||||
-rw-r--r-- | arch/mips/mips-boards/generic/init.c | 343 | ||||
-rw-r--r-- | arch/mips/mips-boards/generic/memory.c | 173 | ||||
-rw-r--r-- | arch/mips/mips-boards/generic/mipsIRQ.S | 153 | ||||
-rw-r--r-- | arch/mips/mips-boards/generic/pci.c | 163 | ||||
-rw-r--r-- | arch/mips/mips-boards/generic/printf.c | 79 | ||||
-rw-r--r-- | arch/mips/mips-boards/generic/reset.c | 73 | ||||
-rw-r--r-- | arch/mips/mips-boards/generic/time.c | 167 |
11 files changed, 1408 insertions, 0 deletions
diff --git a/arch/mips/mips-boards/generic/Makefile b/arch/mips/mips-boards/generic/Makefile new file mode 100644 index 00000000000..b21bc6887fa --- /dev/null +++ b/arch/mips/mips-boards/generic/Makefile @@ -0,0 +1,26 @@ +# +# Carsten Langgaard, carstenl@mips.com +# Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved. +# +# This program is free software; you can distribute it and/or modify it +# under the terms of the GNU General Public License (Version 2) as +# published by the Free Software Foundation. +# +# This program is distributed in the hope it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# for more details. +# +# 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., +# 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# Makefile for the MIPS boards generic routines under Linux. +# + +obj-y := mipsIRQ.o reset.o display.o init.o memory.o \ + printf.o cmdline.o time.o +obj-$(CONFIG_PCI) += pci.o +obj-$(CONFIG_KGDB) += gdb_hook.o + +EXTRA_AFLAGS := $(CFLAGS) diff --git a/arch/mips/mips-boards/generic/cmdline.c b/arch/mips/mips-boards/generic/cmdline.c new file mode 100644 index 00000000000..1871c30ed2e --- /dev/null +++ b/arch/mips/mips-boards/generic/cmdline.c @@ -0,0 +1,59 @@ +/* + * Carsten Langgaard, carstenl@mips.com + * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved. + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * 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., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Kernel command line creation using the prom monitor (YAMON) argc/argv. + */ +#include <linux/init.h> +#include <linux/string.h> + +#include <asm/bootinfo.h> + +extern int prom_argc; +extern int *_prom_argv; + +/* + * YAMON (32-bit PROM) pass arguments and environment as 32-bit pointer. + * This macro take care of sign extension. + */ +#define prom_argv(index) ((char *)(long)_prom_argv[(index)]) + +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'; + } +} diff --git a/arch/mips/mips-boards/generic/display.c b/arch/mips/mips-boards/generic/display.c new file mode 100644 index 00000000000..f653946afc2 --- /dev/null +++ b/arch/mips/mips-boards/generic/display.c @@ -0,0 +1,39 @@ +/* + * Carsten Langgaard, carstenl@mips.com + * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved. + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * 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., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Display routines for display messages in MIPS boards ascii display. + */ + +#include <linux/compiler.h> +#include <asm/io.h> +#include <asm/mips-boards/generic.h> + +void mips_display_message(const char *str) +{ + static volatile unsigned int *display = NULL; + int i; + + if (unlikely(display == NULL)) + display = (volatile unsigned int *)ioremap(ASCII_DISPLAY_POS_BASE, 16*sizeof(int)); + + for (i = 0; i <= 14; i=i+2) { + if (*str) + display[i] = *str++; + else + display[i] = ' '; + } +} diff --git a/arch/mips/mips-boards/generic/gdb_hook.c b/arch/mips/mips-boards/generic/gdb_hook.c new file mode 100644 index 00000000000..91a2ccbe373 --- /dev/null +++ b/arch/mips/mips-boards/generic/gdb_hook.c @@ -0,0 +1,133 @@ +/* + * Carsten Langgaard, carstenl@mips.com + * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * 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., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * This is the interface to the remote debugger stub. + */ +#include <linux/types.h> +#include <linux/serial.h> +#include <linux/serialP.h> +#include <linux/serial_reg.h> + +#include <asm/serial.h> +#include <asm/io.h> + +static struct serial_state rs_table[RS_TABLE_SIZE] = { + SERIAL_PORT_DFNS /* Defined in serial.h */ +}; + +static struct async_struct kdb_port_info = {0}; + +int (*generic_putDebugChar)(char); +char (*generic_getDebugChar)(void); + +static __inline__ unsigned int serial_in(struct async_struct *info, int offset) +{ + return inb(info->port + offset); +} + +static __inline__ void serial_out(struct async_struct *info, int offset, + int value) +{ + outb(value, info->port+offset); +} + +int rs_kgdb_hook(int tty_no, int speed) { + int t; + struct serial_state *ser = &rs_table[tty_no]; + + kdb_port_info.state = ser; + kdb_port_info.magic = SERIAL_MAGIC; + kdb_port_info.port = ser->port; + kdb_port_info.flags = ser->flags; + + /* + * Clear all interrupts + */ + serial_in(&kdb_port_info, UART_LSR); + serial_in(&kdb_port_info, UART_RX); + serial_in(&kdb_port_info, UART_IIR); + serial_in(&kdb_port_info, UART_MSR); + + /* + * Now, initialize the UART + */ + serial_out(&kdb_port_info, UART_LCR, UART_LCR_WLEN8); /* reset DLAB */ + if (kdb_port_info.flags & ASYNC_FOURPORT) { + kdb_port_info.MCR = UART_MCR_DTR | UART_MCR_RTS; + t = UART_MCR_DTR | UART_MCR_OUT1; + } else { + kdb_port_info.MCR + = UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2; + t = UART_MCR_DTR | UART_MCR_RTS; + } + + kdb_port_info.MCR = t; /* no interrupts, please */ + serial_out(&kdb_port_info, UART_MCR, kdb_port_info.MCR); + + /* + * and set the speed of the serial port + */ + if (speed == 0) + speed = 9600; + + t = kdb_port_info.state->baud_base / speed; + /* set DLAB */ + serial_out(&kdb_port_info, UART_LCR, UART_LCR_WLEN8 | UART_LCR_DLAB); + serial_out(&kdb_port_info, UART_DLL, t & 0xff);/* LS of divisor */ + serial_out(&kdb_port_info, UART_DLM, t >> 8); /* MS of divisor */ + /* reset DLAB */ + serial_out(&kdb_port_info, UART_LCR, UART_LCR_WLEN8); + + return speed; +} + +int putDebugChar(char c) +{ + return generic_putDebugChar(c); +} + +char getDebugChar(void) +{ + return generic_getDebugChar(); +} + +int rs_putDebugChar(char c) +{ + + if (!kdb_port_info.state) { /* need to init device first */ + return 0; + } + + while ((serial_in(&kdb_port_info, UART_LSR) & UART_LSR_THRE) == 0) + ; + + serial_out(&kdb_port_info, UART_TX, c); + + return 1; +} + +char rs_getDebugChar(void) +{ + if (!kdb_port_info.state) { /* need to init device first */ + return 0; + } + + while (!(serial_in(&kdb_port_info, UART_LSR) & 1)) + ; + + return serial_in(&kdb_port_info, UART_RX); +} diff --git a/arch/mips/mips-boards/generic/init.c b/arch/mips/mips-boards/generic/init.c new file mode 100644 index 00000000000..31caf0603a3 --- /dev/null +++ b/arch/mips/mips-boards/generic/init.c @@ -0,0 +1,343 @@ +/* + * Carsten Langgaard, carstenl@mips.com + * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved. + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * 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., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * PROM library initialisation code. + */ +#include <linux/config.h> +#include <linux/init.h> +#include <linux/string.h> +#include <linux/kernel.h> + +#include <asm/io.h> +#include <asm/bootinfo.h> +#include <asm/mips-boards/prom.h> +#include <asm/mips-boards/generic.h> +#ifdef CONFIG_MIPS_GT64120 +#include <asm/gt64120.h> +#endif +#include <asm/mips-boards/msc01_pci.h> +#include <asm/mips-boards/bonito64.h> +#ifdef CONFIG_MIPS_MALTA +#include <asm/mips-boards/malta.h> +#endif + +#ifdef CONFIG_KGDB +extern int rs_kgdb_hook(int, int); +extern int rs_putDebugChar(char); +extern char rs_getDebugChar(void); +extern int saa9730_kgdb_hook(int); +extern int saa9730_putDebugChar(char); +extern char saa9730_getDebugChar(void); +#endif + +int prom_argc; +int *_prom_argv, *_prom_envp; + +/* + * YAMON (32-bit PROM) pass arguments and environment as 32-bit pointer. + * This macro take care of sign extension, if running in 64-bit mode. + */ +#define prom_envp(index) ((char *)(long)_prom_envp[(index)]) + +int init_debug = 0; + +unsigned int mips_revision_corid; + +/* Bonito64 system controller register base. */ +unsigned long _pcictrl_bonito; +unsigned long _pcictrl_bonito_pcicfg; + +/* GT64120 system controller register base */ +unsigned long _pcictrl_gt64120; + +/* MIPS System controller register base */ +unsigned long _pcictrl_msc; + +char *prom_getenv(char *envname) +{ + /* + * Return a pointer to the given environment variable. + * In 64-bit mode: we're using 64-bit pointers, but all pointers + * in the PROM structures are only 32-bit, so we need some + * workarounds, if we are running in 64-bit mode. + */ + int i, index=0; + + i = strlen(envname); + + while (prom_envp(index)) { + if(strncmp(envname, prom_envp(index), i) == 0) { + return(prom_envp(index+1)); + } + index += 2; + } + + return NULL; +} + +static inline unsigned char str2hexnum(unsigned char c) +{ + if (c >= '0' && c <= '9') + return c - '0'; + if (c >= 'a' && c <= 'f') + return c - 'a' + 10; + return 0; /* foo */ +} + +static inline void str2eaddr(unsigned char *ea, unsigned char *str) +{ + int i; + + for (i = 0; i < 6; i++) { + unsigned char num; + + if((*str == '.') || (*str == ':')) + str++; + num = str2hexnum(*str++) << 4; + num |= (str2hexnum(*str++)); + ea[i] = num; + } +} + +int get_ethernet_addr(char *ethernet_addr) +{ + char *ethaddr_str; + + ethaddr_str = prom_getenv("ethaddr"); + if (!ethaddr_str) { + printk("ethaddr not set in boot prom\n"); + return -1; + } + str2eaddr(ethernet_addr, ethaddr_str); + + if (init_debug > 1) { + int i; + printk("get_ethernet_addr: "); + for (i=0; i<5; i++) + printk("%02x:", (unsigned char)*(ethernet_addr+i)); + printk("%02x\n", *(ethernet_addr+i)); + } + + return 0; +} + +#ifdef CONFIG_SERIAL_8250_CONSOLE +static void __init console_config(void) +{ + char console_string[40]; + int baud = 0; + char parity = '\0', bits = '\0', flow = '\0'; + char *s; + + if ((strstr(prom_getcmdline(), "console=ttyS")) == NULL) { + s = prom_getenv("modetty0"); + if (s) { + while (*s >= '0' && *s <= '9') + baud = baud*10 + *s++ - '0'; + if (*s == ',') s++; + if (*s) parity = *s++; + if (*s == ',') s++; + if (*s) bits = *s++; + if (*s == ',') s++; + if (*s == 'h') flow = 'r'; + } + if (baud == 0) + baud = 38400; + if (parity != 'n' && parity != 'o' && parity != 'e') + parity = 'n'; + if (bits != '7' && bits != '8') + bits = '8'; + if (flow == '\0') + flow = 'r'; + sprintf (console_string, " console=ttyS0,%d%c%c%c", baud, parity, bits, flow); + strcat (prom_getcmdline(), console_string); + prom_printf("Config serial console:%s\n", console_string); + } +} +#endif + +#ifdef CONFIG_KGDB +void __init kgdb_config (void) +{ + extern int (*generic_putDebugChar)(char); + extern char (*generic_getDebugChar)(void); + char *argptr; + int line, speed; + + argptr = prom_getcmdline(); + if ((argptr = strstr(argptr, "kgdb=ttyS")) != NULL) { + argptr += strlen("kgdb=ttyS"); + if (*argptr != '0' && *argptr != '1') + printk("KGDB: Unknown serial line /dev/ttyS%c, " + "falling back to /dev/ttyS1\n", *argptr); + line = *argptr == '0' ? 0 : 1; + printk("KGDB: Using serial line /dev/ttyS%d for session\n", line); + + speed = 0; + if (*++argptr == ',') + { + int c; + while ((c = *++argptr) && ('0' <= c && c <= '9')) + speed = speed * 10 + c - '0'; + } +#ifdef CONFIG_MIPS_ATLAS + if (line == 1) { + speed = saa9730_kgdb_hook(speed); + generic_putDebugChar = saa9730_putDebugChar; + generic_getDebugChar = saa9730_getDebugChar; + } + else +#endif + { + speed = rs_kgdb_hook(line, speed); + generic_putDebugChar = rs_putDebugChar; + generic_getDebugChar = rs_getDebugChar; + } + + prom_printf("KGDB: Using serial line /dev/ttyS%d at %d for session, " + "please connect your debugger\n", line ? 1 : 0, speed); + + { + char *s; + for (s = "Please connect GDB to this port\r\n"; *s; ) + generic_putDebugChar (*s++); + } + + kgdb_enabled = 1; + /* Breakpoint is invoked after interrupts are initialised */ + } +} +#endif + +void __init prom_init(void) +{ + prom_argc = fw_arg0; + _prom_argv = (int *) fw_arg1; + _prom_envp = (int *) fw_arg2; + + mips_display_message("LINUX"); + +#ifdef CONFIG_MIPS_SEAD + set_io_port_base(KSEG1); +#else + /* + * early setup of _pcictrl_bonito so that we can determine + * the system controller on a CORE_EMUL board + */ + _pcictrl_bonito = (unsigned long)ioremap(BONITO_REG_BASE, BONITO_REG_SIZE); + + mips_revision_corid = MIPS_REVISION_CORID; + + if (mips_revision_corid == MIPS_REVISION_CORID_CORE_EMUL) { + if (BONITO_PCIDID == 0x0001df53 || + BONITO_PCIDID == 0x0003df53) + mips_revision_corid = MIPS_REVISION_CORID_CORE_EMUL_BON; + else + mips_revision_corid = MIPS_REVISION_CORID_CORE_EMUL_MSC; + } + switch(mips_revision_corid) { + case MIPS_REVISION_CORID_QED_RM5261: + case MIPS_REVISION_CORID_CORE_LV: + case MIPS_REVISION_CORID_CORE_FPGA: + case MIPS_REVISION_CORID_CORE_FPGAR2: + /* + * Setup the North bridge to do Master byte-lane swapping + * when running in bigendian. + */ + _pcictrl_gt64120 = (unsigned long)ioremap(MIPS_GT_BASE, 0x2000); + +#ifdef CONFIG_CPU_LITTLE_ENDIAN + GT_WRITE(GT_PCI0_CMD_OFS, GT_PCI0_CMD_MBYTESWAP_BIT | + GT_PCI0_CMD_SBYTESWAP_BIT); +#else + GT_WRITE(GT_PCI0_CMD_OFS, 0); +#endif + +#ifdef CONFIG_MIPS_MALTA + set_io_port_base(MALTA_GT_PORT_BASE); +#else + set_io_port_base((unsigned long)ioremap(0, 0x20000000)); +#endif + break; + + case MIPS_REVISION_CORID_CORE_EMUL_BON: + case MIPS_REVISION_CORID_BONITO64: + case MIPS_REVISION_CORID_CORE_20K: + _pcictrl_bonito_pcicfg = (unsigned long)ioremap(BONITO_PCICFG_BASE, BONITO_PCICFG_SIZE); + + /* + * Disable Bonito IOBC. + */ + BONITO_PCIMEMBASECFG = BONITO_PCIMEMBASECFG & + ~(BONITO_PCIMEMBASECFG_MEMBASE0_CACHED | + BONITO_PCIMEMBASECFG_MEMBASE1_CACHED); + + /* + * Setup the North bridge to do Master byte-lane swapping + * when running in bigendian. + */ +#ifdef CONFIG_CPU_LITTLE_ENDIAN + BONITO_BONGENCFG = BONITO_BONGENCFG & + ~(BONITO_BONGENCFG_MSTRBYTESWAP | + BONITO_BONGENCFG_BYTESWAP); +#else + BONITO_BONGENCFG = BONITO_BONGENCFG | + BONITO_BONGENCFG_MSTRBYTESWAP | + BONITO_BONGENCFG_BYTESWAP; +#endif + +#ifdef CONFIG_MIPS_MALTA + set_io_port_base(MALTA_BONITO_PORT_BASE); +#else + set_io_port_base((unsigned long)ioremap(0, 0x20000000)); +#endif + break; + + case MIPS_REVISION_CORID_CORE_MSC: + case MIPS_REVISION_CORID_CORE_FPGA2: + case MIPS_REVISION_CORID_CORE_EMUL_MSC: + _pcictrl_msc = (unsigned long)ioremap(MIPS_MSC01_PCI_REG_BASE, 0x2000); + +#ifdef CONFIG_CPU_LITTLE_ENDIAN + MSC_WRITE(MSC01_PCI_SWAP, MSC01_PCI_SWAP_NOSWAP); +#else + MSC_WRITE(MSC01_PCI_SWAP, + MSC01_PCI_SWAP_BYTESWAP << MSC01_PCI_SWAP_IO_SHF | + MSC01_PCI_SWAP_BYTESWAP << MSC01_PCI_SWAP_MEM_SHF | + MSC01_PCI_SWAP_BYTESWAP << MSC01_PCI_SWAP_BAR0_SHF); +#endif + +#ifdef CONFIG_MIPS_MALTA + set_io_port_base(MALTA_MSC_PORT_BASE); +#else + set_io_port_base((unsigned long)ioremap(0, 0x20000000)); +#endif + break; + + default: + /* Unknown Core card */ + mips_display_message("CC Error"); + while(1); /* We die here... */ + } +#endif + prom_printf("\nLINUX started...\n"); + prom_init_cmdline(); + prom_meminit(); +#ifdef CONFIG_SERIAL_8250_CONSOLE + console_config(); +#endif +} diff --git a/arch/mips/mips-boards/generic/memory.c b/arch/mips/mips-boards/generic/memory.c new file mode 100644 index 00000000000..5ae2b43e4c2 --- /dev/null +++ b/arch/mips/mips-boards/generic/memory.c @@ -0,0 +1,173 @@ +/* + * Carsten Langgaard, carstenl@mips.com + * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved. + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * 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., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * PROM library functions for acquiring/using memory descriptors given to + * us from the YAMON. + */ +#include <linux/config.h> +#include <linux/init.h> +#include <linux/mm.h> +#include <linux/bootmem.h> + +#include <asm/bootinfo.h> +#include <asm/page.h> + +#include <asm/mips-boards/prom.h> + +/*#define DEBUG*/ + +enum yamon_memtypes { + yamon_dontuse, + yamon_prom, + yamon_free, +}; +struct prom_pmemblock mdesc[PROM_MAX_PMEMBLOCKS]; + +#ifdef DEBUG +static char *mtypes[3] = { + "Dont use memory", + "YAMON PROM memory", + "Free memmory", +}; +#endif + +/* References to section boundaries */ +extern char _end; + +#define PFN_ALIGN(x) (((unsigned long)(x) + (PAGE_SIZE - 1)) & PAGE_MASK) + + +struct prom_pmemblock * __init prom_getmdesc(void) +{ + char *memsize_str; + unsigned int memsize; + + memsize_str = prom_getenv("memsize"); + if (!memsize_str) { + prom_printf("memsize not set in boot prom, set to default (32Mb)\n"); + memsize = 0x02000000; + } else { +#ifdef DEBUG + prom_printf("prom_memsize = %s\n", memsize_str); +#endif + memsize = simple_strtol(memsize_str, NULL, 0); + } + + memset(mdesc, 0, sizeof(mdesc)); + + mdesc[0].type = yamon_dontuse; + mdesc[0].base = 0x00000000; + mdesc[0].size = 0x00001000; + + mdesc[1].type = yamon_prom; + mdesc[1].base = 0x00001000; + mdesc[1].size = 0x000ef000; + +#ifdef CONFIG_MIPS_MALTA + /* + * The area 0x000f0000-0x000fffff is allocated for BIOS memory by the + * south bridge and PCI access always forwarded to the ISA Bus and + * BIOSCS# is always generated. + * This mean that this area can't be used as DMA memory for PCI + * devices. + */ + mdesc[2].type = yamon_dontuse; + mdesc[2].base = 0x000f0000; + mdesc[2].size = 0x00010000; +#else + mdesc[2].type = yamon_prom; + mdesc[2].base = 0x000f0000; + mdesc[2].size = 0x00010000; +#endif + + mdesc[3].type = yamon_dontuse; + mdesc[3].base = 0x00100000; + mdesc[3].size = CPHYSADDR(PFN_ALIGN(&_end)) - mdesc[3].base; + + mdesc[4].type = yamon_free; + mdesc[4].base = CPHYSADDR(PFN_ALIGN(&_end)); + mdesc[4].size = memsize - mdesc[4].base; + + return &mdesc[0]; +} + +static int __init prom_memtype_classify (unsigned int type) +{ + switch (type) { + case yamon_free: + return BOOT_MEM_RAM; + case yamon_prom: + return BOOT_MEM_ROM_DATA; + default: + return BOOT_MEM_RESERVED; + } +} + +void __init prom_meminit(void) +{ + struct prom_pmemblock *p; + +#ifdef DEBUG + prom_printf("YAMON MEMORY DESCRIPTOR dump:\n"); + p = prom_getmdesc(); + while (p->size) { + int i = 0; + prom_printf("[%d,%p]: base<%08lx> size<%08lx> type<%s>\n", + i, p, p->base, p->size, mtypes[p->type]); + p++; + i++; + } +#endif + p = prom_getmdesc(); + + while (p->size) { + long type; + unsigned long base, size; + + type = prom_memtype_classify (p->type); + base = p->base; + size = p->size; + + add_memory_region(base, size, type); + p++; + } +} + +unsigned long __init prom_free_prom_memory(void) +{ + unsigned long freed = 0; + unsigned long addr; + int i; + + for (i = 0; i < boot_mem_map.nr_map; i++) { + if (boot_mem_map.map[i].type != BOOT_MEM_ROM_DATA) + continue; + + addr = boot_mem_map.map[i].addr; + while (addr < boot_mem_map.map[i].addr + + boot_mem_map.map[i].size) { + ClearPageReserved(virt_to_page(__va(addr))); + set_page_count(virt_to_page(__va(addr)), 1); + free_page((unsigned long)__va(addr)); + addr += PAGE_SIZE; + freed += PAGE_SIZE; + } + } + printk("Freeing prom memory: %ldkb freed\n", freed >> 10); + + return freed; +} diff --git a/arch/mips/mips-boards/generic/mipsIRQ.S b/arch/mips/mips-boards/generic/mipsIRQ.S new file mode 100644 index 00000000000..131f49bccb2 --- /dev/null +++ b/arch/mips/mips-boards/generic/mipsIRQ.S @@ -0,0 +1,153 @@ +/* + * Carsten Langgaard, carstenl@mips.com + * Copyright (C) 1999, 2000 MIPS Technologies, Inc. All rights reserved. + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * 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., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + * + * Interrupt exception dispatch code. + * + */ +#include <linux/config.h> + +#include <asm/asm.h> +#include <asm/mipsregs.h> +#include <asm/regdef.h> +#include <asm/stackframe.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. + * + * Furthermore, the IRQs on the MIPS board look basically (barring software + * IRQs which we don't use at all and all external interrupt sources are + * combined together on hardware interrupt 0 (MIPS IRQ 2)) like: + * + * MIPS IRQ Source + * -------- ------ + * 0 Software (ignored) + * 1 Software (ignored) + * 2 Combined hardware interrupt (hw0) + * 3 Hardware (ignored) + * 4 Hardware (ignored) + * 5 Hardware (ignored) + * 6 Hardware (ignored) + * 7 R4k timer (what we use) + * + * Note: On the SEAD board thing are a little bit different. + * Here IRQ 2 (hw0) is wired to the UART0 and IRQ 3 (hw1) is wired + * wired to UART1. + * + * We handle the IRQ according to _our_ priority which is: + * + * Highest ---- R4k Timer + * Lowest ---- Combined hardware interrupt + * + * then we just return, if multiple IRQs are pending then we will just take + * another exception, big deal. + */ + + .text + .set noreorder + .set noat + .align 5 + NESTED(mipsIRQ, PT_SIZE, sp) + SAVE_ALL + CLI + .set at + + mfc0 s0, CP0_CAUSE # get irq bits + mfc0 s1, CP0_STATUS # get irq mask + and s0, s1 + + /* First we check for r4k counter/timer IRQ. */ + andi a0, s0, CAUSEF_IP7 + beq a0, zero, 1f + andi a0, s0, CAUSEF_IP2 # delay slot, check hw0 interrupt + + /* Wheee, a timer interrupt. */ + move a0, sp + jal mips_timer_interrupt + nop + + j ret_from_irq + nop + +1: +#if defined(CONFIG_MIPS_SEAD) + beq a0, zero, 1f + andi a0, s0, CAUSEF_IP3 # delay slot, check hw1 interrupt +#else + beq a0, zero, 1f # delay slot, check hw3 interrupt + andi a0, s0, CAUSEF_IP5 +#endif + + /* Wheee, combined hardware level zero interrupt. */ +#if defined(CONFIG_MIPS_ATLAS) + jal atlas_hw0_irqdispatch +#elif defined(CONFIG_MIPS_MALTA) + jal malta_hw0_irqdispatch +#elif defined(CONFIG_MIPS_SEAD) + jal sead_hw0_irqdispatch +#else +#error "MIPS board not supported\n" +#endif + move a0, sp # delay slot + + j ret_from_irq + nop # delay slot + +1: +#if defined(CONFIG_MIPS_SEAD) + beq a0, zero, 1f + andi a0, s0, CAUSEF_IP5 # delay slot, check hw3 interrupt + jal sead_hw1_irqdispatch + move a0, sp # delay slot + j ret_from_irq + nop # delay slot +1: +#endif +#if defined(CONFIG_MIPS_MALTA) + beq a0, zero, 1f # check hw3 (coreHI) interrupt + nop + jal corehi_irqdispatch + move a0, sp + j ret_from_irq + nop +1: +#endif + /* + * Here by mistake? This is possible, what can happen is that by the + * time we take the exception the IRQ pin goes low, so just leave if + * this is the case. + */ + move a1,s0 + PRINT("Got interrupt: c0_cause = %08x\n") + mfc0 a1, CP0_EPC + PRINT("c0_epc = %08x\n") + + j ret_from_irq + nop + END(mipsIRQ) diff --git a/arch/mips/mips-boards/generic/pci.c b/arch/mips/mips-boards/generic/pci.c new file mode 100644 index 00000000000..92c34bda02a --- /dev/null +++ b/arch/mips/mips-boards/generic/pci.c @@ -0,0 +1,163 @@ +/* + * Carsten Langgaard, carstenl@mips.com + * Copyright (C) 1999, 2000 MIPS Technologies, Inc. All rights reserved. + * + * Copyright (C) 2004 by Ralf Baechle (ralf@linux-mips.org) + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * 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., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * MIPS boards specific PCI support. + */ +#include <linux/config.h> +#include <linux/types.h> +#include <linux/pci.h> +#include <linux/kernel.h> +#include <linux/init.h> + +#include <asm/mips-boards/generic.h> +#include <asm/gt64120.h> +#include <asm/mips-boards/bonito64.h> +#include <asm/mips-boards/msc01_pci.h> +#ifdef CONFIG_MIPS_MALTA +#include <asm/mips-boards/malta.h> +#endif + +static struct resource bonito64_mem_resource = { + .name = "Bonito PCI MEM", + .start = 0x10000000UL, + .end = 0x1bffffffUL, + .flags = IORESOURCE_MEM, +}; + +static struct resource bonito64_io_resource = { + .name = "Bonito IO MEM", + .start = 0x00002000UL, /* avoid conflicts with YAMON allocated I/O addresses */ + .end = 0x000fffffUL, + .flags = IORESOURCE_IO, +}; + +static struct resource gt64120_mem_resource = { + .name = "GT64120 PCI MEM", + .start = 0x10000000UL, + .end = 0x1bdfffffUL, + .flags = IORESOURCE_MEM, +}; + +static struct resource gt64120_io_resource = { + .name = "GT64120 IO MEM", +#ifdef CONFIG_MIPS_ATLAS + .start = 0x18000000UL, + .end = 0x181fffffUL, +#endif +#ifdef CONFIG_MIPS_MALTA + .start = 0x00002000UL, + .end = 0x001fffffUL, +#endif + .flags = IORESOURCE_IO, +}; + +static struct resource msc_mem_resource = { + .name = "MSC PCI MEM", + .start = 0x10000000UL, + .end = 0x1fffffffUL, + .flags = IORESOURCE_MEM, +}; + +static struct resource msc_io_resource = { + .name = "MSC IO MEM", + .start = 0x00002000UL, + .end = 0x007fffffUL, + .flags = IORESOURCE_IO, +}; + +extern struct pci_ops bonito64_pci_ops; +extern struct pci_ops gt64120_pci_ops; +extern struct pci_ops msc_pci_ops; + +static struct pci_controller bonito64_controller = { + .pci_ops = &bonito64_pci_ops, + .io_resource = &bonito64_io_resource, + .mem_resource = &bonito64_mem_resource, + .mem_offset = 0x10000000UL, + .io_offset = 0x00000000UL, +}; + +static struct pci_controller gt64120_controller = { + .pci_ops = >64120_pci_ops, + .io_resource = >64120_io_resource, + .mem_resource = >64120_mem_resource, + .mem_offset = 0x00000000UL, + .io_offset = 0x00000000UL, +}; + +static struct pci_controller msc_controller = { + .pci_ops = &msc_pci_ops, + .io_resource = &msc_io_resource, + .mem_resource = &msc_mem_resource, + .mem_offset = 0x10000000UL, + .io_offset = 0x00000000UL, +}; + +static int __init pcibios_init(void) +{ + struct pci_controller *controller; + + switch (mips_revision_corid) { + case MIPS_REVISION_CORID_QED_RM5261: + case MIPS_REVISION_CORID_CORE_LV: + case MIPS_REVISION_CORID_CORE_FPGA: + case MIPS_REVISION_CORID_CORE_FPGAR2: + /* + * Due to a bug in the Galileo system controller, we need + * to setup the PCI BAR for the Galileo internal registers. + * This should be done in the bios/bootprom and will be + * fixed in a later revision of YAMON (the MIPS boards + * boot prom). + */ + GT_WRITE(GT_PCI0_CFGADDR_OFS, + (0 << GT_PCI0_CFGADDR_BUSNUM_SHF) | /* Local bus */ + (0 << GT_PCI0_CFGADDR_DEVNUM_SHF) | /* GT64120 dev */ + (0 << GT_PCI0_CFGADDR_FUNCTNUM_SHF) | /* Function 0*/ + ((0x20/4) << GT_PCI0_CFGADDR_REGNUM_SHF) | /* BAR 4*/ + GT_PCI0_CFGADDR_CONFIGEN_BIT ); + + /* Perform the write */ + GT_WRITE(GT_PCI0_CFGDATA_OFS, CPHYSADDR(MIPS_GT_BASE)); + + controller = >64120_controller; + break; + + case MIPS_REVISION_CORID_BONITO64: + case MIPS_REVISION_CORID_CORE_20K: + case MIPS_REVISION_CORID_CORE_EMUL_BON: + controller = &bonito64_controller; + break; + + case MIPS_REVISION_CORID_CORE_MSC: + case MIPS_REVISION_CORID_CORE_FPGA2: + case MIPS_REVISION_CORID_CORE_EMUL_MSC: + controller = &msc_controller; + break; + default: + return 1; + } + + ioport_resource.end = controller->io_resource->end; + + register_pci_controller (controller); + + return 0; +} + +early_initcall(pcibios_init); diff --git a/arch/mips/mips-boards/generic/printf.c b/arch/mips/mips-boards/generic/printf.c new file mode 100644 index 00000000000..2c1ab1f19fd --- /dev/null +++ b/arch/mips/mips-boards/generic/printf.c @@ -0,0 +1,79 @@ +/* + * Carsten Langgaard, carstenl@mips.com + * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved. + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * 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., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Putting things on the screen/serial line using YAMONs facilities. + */ +#include <linux/config.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/serial_reg.h> +#include <linux/spinlock.h> +#include <asm/io.h> + +#ifdef CONFIG_MIPS_ATLAS +#include <asm/mips-boards/atlas.h> + +#ifdef CONFIG_CPU_LITTLE_ENDIAN +#define PORT(offset) (ATLAS_UART_REGS_BASE + ((offset)<<3)) +#else +#define PORT(offset) (ATLAS_UART_REGS_BASE + 3 + ((offset)<<3)) +#endif + +#elif defined(CONFIG_MIPS_SEAD) + +#include <asm/mips-boards/sead.h> + +#ifdef CONFIG_CPU_LITTLE_ENDIAN +#define PORT(offset) (SEAD_UART0_REGS_BASE + ((offset)<<3)) +#else +#define PORT(offset) (SEAD_UART0_REGS_BASE + 3 + ((offset)<<3)) +#endif + +#else + +#define PORT(offset) (0x3f8 + (offset)) + +#endif + +static inline unsigned int serial_in(int offset) +{ + return inb(PORT(offset)); +} + +static inline void serial_out(int offset, int value) +{ + outb(value, PORT(offset)); +} + +int prom_putchar(char c) +{ + while ((serial_in(UART_LSR) & UART_LSR_THRE) == 0) + ; + + serial_out(UART_TX, c); + + return 1; +} + +char prom_getchar(void) +{ + while (!(serial_in(UART_LSR) & UART_LSR_DR)) + ; + + return serial_in(UART_RX); +} + diff --git a/arch/mips/mips-boards/generic/reset.c b/arch/mips/mips-boards/generic/reset.c new file mode 100644 index 00000000000..9fdec743bd9 --- /dev/null +++ b/arch/mips/mips-boards/generic/reset.c @@ -0,0 +1,73 @@ +/* + * Carsten Langgaard, carstenl@mips.com + * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved. + * + * ######################################################################## + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * 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., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * ######################################################################## + * + * Reset the MIPS boards. + * + */ +#include <linux/config.h> + +#include <asm/io.h> +#include <asm/reboot.h> +#include <asm/mips-boards/generic.h> +#if defined(CONFIG_MIPS_ATLAS) +#include <asm/mips-boards/atlas.h> +#endif + +static void mips_machine_restart(char *command); +static void mips_machine_halt(void); +#if defined(CONFIG_MIPS_ATLAS) +static void atlas_machine_power_off(void); +#endif + +static void mips_machine_restart(char *command) +{ + volatile unsigned int *softres_reg = (unsigned int *)ioremap (SOFTRES_REG, sizeof(unsigned int)); + + *softres_reg = GORESET; +} + +static void mips_machine_halt(void) +{ + volatile unsigned int *softres_reg = (unsigned int *)ioremap (SOFTRES_REG, sizeof(unsigned int)); + + *softres_reg = GORESET; +} + +#if defined(CONFIG_MIPS_ATLAS) +static void atlas_machine_power_off(void) +{ + volatile unsigned int *psustby_reg = (unsigned int *)ioremap(ATLAS_PSUSTBY_REG, sizeof(unsigned int)); + + *psustby_reg = ATLAS_GOSTBY; +} +#endif + +void mips_reboot_setup(void) +{ + _machine_restart = mips_machine_restart; + _machine_halt = mips_machine_halt; +#if defined(CONFIG_MIPS_ATLAS) + _machine_power_off = atlas_machine_power_off; +#endif +#if defined(CONFIG_MIPS_MALTA) || defined(CONFIG_MIPS_SEAD) + _machine_power_off = mips_machine_halt; +#endif +} diff --git a/arch/mips/mips-boards/generic/time.c b/arch/mips/mips-boards/generic/time.c new file mode 100644 index 00000000000..fe7fc17305a --- /dev/null +++ b/arch/mips/mips-boards/generic/time.c @@ -0,0 +1,167 @@ +/* + * Carsten Langgaard, carstenl@mips.com + * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved. + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * 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., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Setting up the clock on the MIPS boards. + */ + +#include <linux/types.h> +#include <linux/config.h> +#include <linux/init.h> +#include <linux/kernel_stat.h> +#include <linux/sched.h> +#include <linux/spinlock.h> +#include <linux/interrupt.h> +#include <linux/time.h> +#include <linux/timex.h> +#include <linux/mc146818rtc.h> + +#include <asm/mipsregs.h> +#include <asm/ptrace.h> +#include <asm/div64.h> +#include <asm/cpu.h> +#include <asm/time.h> +#include <asm/mc146818-time.h> + +#include <asm/mips-boards/generic.h> +#include <asm/mips-boards/prom.h> + +unsigned long cpu_khz; + +#if defined(CONFIG_MIPS_SEAD) +#define ALLINTS (IE_IRQ0 | IE_IRQ1 | IE_IRQ5) +#else +#define ALLINTS (IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4 | IE_IRQ5) +#endif + +#if defined(CONFIG_MIPS_ATLAS) +static char display_string[] = " LINUX ON ATLAS "; +#endif +#if defined(CONFIG_MIPS_MALTA) +static char display_string[] = " LINUX ON MALTA "; +#endif +#if defined(CONFIG_MIPS_SEAD) +static char display_string[] = " LINUX ON SEAD "; +#endif +static unsigned int display_count = 0; +#define MAX_DISPLAY_COUNT (sizeof(display_string) - 8) + +#define MIPS_CPU_TIMER_IRQ (NR_IRQS-1) + +static unsigned int timer_tick_count=0; + +void mips_timer_interrupt(struct pt_regs *regs) +{ + if ((timer_tick_count++ % HZ) == 0) { + mips_display_message(&display_string[display_count++]); + if (display_count == MAX_DISPLAY_COUNT) + display_count = 0; + + } + + ll_timer_interrupt(MIPS_CPU_TIMER_IRQ, regs); +} + +/* + * Estimate CPU frequency. Sets mips_counter_frequency as a side-effect + */ +static unsigned int __init estimate_cpu_frequency(void) +{ + unsigned int prid = read_c0_prid() & 0xffff00; + unsigned int count; + +#ifdef CONFIG_MIPS_SEAD + /* + * The SEAD board doesn't have a real time clock, so we can't + * really calculate the timer frequency + * For now we hardwire the SEAD board frequency to 12MHz. + */ + + if ((prid == (PRID_COMP_MIPS | PRID_IMP_20KC)) || + (prid == (PRID_COMP_MIPS | PRID_IMP_25KF))) + count = 12000000; + else + count = 6000000; +#endif +#if defined(CONFIG_MIPS_ATLAS) || defined(CONFIG_MIPS_MALTA) + unsigned int flags; + + local_irq_save(flags); + + /* Start counter exactly on falling edge of update flag */ + while (CMOS_READ(RTC_REG_A) & RTC_UIP); + while (!(CMOS_READ(RTC_REG_A) & RTC_UIP)); + + /* Start r4k counter. */ + write_c0_count(0); + + /* Read counter exactly on falling edge of update flag */ + while (CMOS_READ(RTC_REG_A) & RTC_UIP); + while (!(CMOS_READ(RTC_REG_A) & RTC_UIP)); + + count = read_c0_count(); + + /* restore interrupts */ + local_irq_restore(flags); +#endif + + mips_hpt_frequency = count; + if ((prid != (PRID_COMP_MIPS | PRID_IMP_20KC)) && + (prid != (PRID_COMP_MIPS | PRID_IMP_25KF))) + count *= 2; + + count += 5000; /* round */ + count -= count%10000; + + return count; +} + +unsigned long __init mips_rtc_get_time(void) +{ + return mc146818_get_cmos_time(); +} + +void __init mips_time_init(void) +{ + unsigned int est_freq, flags; + + local_irq_save(flags); + +#if defined(CONFIG_MIPS_ATLAS) || defined(CONFIG_MIPS_MALTA) + /* Set Data mode - binary. */ + CMOS_WRITE(CMOS_READ(RTC_CONTROL) | RTC_DM_BINARY, RTC_CONTROL); +#endif + + est_freq = estimate_cpu_frequency (); + + printk("CPU frequency %d.%02d MHz\n", est_freq/1000000, + (est_freq%1000000)*100/1000000); + + cpu_khz = est_freq / 1000; + + local_irq_restore(flags); +} + +void __init mips_timer_setup(struct irqaction *irq) +{ + /* we are using the cpu counter for timer interrupts */ + irq->handler = no_action; /* we use our own handler */ + setup_irq(MIPS_CPU_TIMER_IRQ, irq); + + /* to generate the first timer interrupt */ + write_c0_compare (read_c0_count() + mips_hpt_frequency/HZ); + set_c0_status(ALLINTS); +} |