- Add IRQ controller (hacked from irq-rm9000.c) - Add Interrupt handlers - Add Sequoia platform compile to Makefile - Add PMON2000 (boot loader) hand-over code - Add Sequoia setup code - Add flags for platform - Add reg defns and macros for RM915x/MSP85x0 Signed-off-by: Kiran Kumar Thota <kiran_thota@xxxxxxxxxxxxxx> diff -Naur a/arch/mips/pmc-sierra/sequoia/irq.c b/arch/mips/pmc-sierra/sequoia/irq.c --- a/arch/mips/pmc-sierra/sequoia/irq.c 1969-12-31 16:00:00.000000000 -0800 +++ b/arch/mips/pmc-sierra/sequoia/irq.c 2006-06-23 14:35:21.000000000 -0700 @@ -0,0 +1,224 @@ +/* + * Copyright (C) 2003 Ralf Baechle + * + * 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. + * + * Handler for RM9000 extended interrupts. These are a non-standard + * feature so we handle them separately from standard interrupts. + */ +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/kernel.h> +#include <linux/module.h> + +#include <asm/irq_cpu.h> +#include <asm/mipsregs.h> +#include <asm/system.h> +#include <asm/pmc_sequoia.h> + +static int irq_base; + +static inline void unmask_rm9k_irq(unsigned int irq) +{ + set_c0_intcontrol(0x1000 << (irq - irq_base)); +} + +static inline void mask_rm9k_irq(unsigned int irq) +{ + clear_c0_intcontrol(0x1000 << (irq - irq_base)); +} + +static inline void rm9k_cpu_irq_enable(unsigned int irq) +{ + unsigned long flags; + + /* convert PCI irq numbers to cp0_intmask bit */ + irq = (10 < irq < 15)? 11 : irq; + local_irq_save(flags); + if (irq == 11) + set_c0_intcontrol(0x100 << 3); + else + unmask_rm9k_irq(irq); + + local_irq_restore(flags); +} + +static void rm9k_cpu_irq_disable(unsigned int irq) +{ + unsigned long flags; + + /* convert PCI irq numbers to cp0_intmask bit */ + irq = (10 < irq < 15)? 11 : irq; + local_irq_save(flags); + if (irq == 11) + clear_c0_intcontrol(0x100 << 3); + else + mask_rm9k_irq(irq); + + local_irq_restore(flags); +} + +static unsigned int rm9k_cpu_irq_startup(unsigned int irq) +{ + rm9k_cpu_irq_enable(irq); + + return 0; +} + +#define rm9k_cpu_irq_shutdown rm9k_cpu_irq_disable + +/* + * Performance counter interrupts are global on all processors. + */ +static void local_rm9k_perfcounter_irq_startup(void *args) +{ + unsigned int irq = (unsigned int) args; + + rm9k_cpu_irq_enable(irq); +} + +static unsigned int rm9k_perfcounter_irq_startup(unsigned int irq) +{ + on_each_cpu(local_rm9k_perfcounter_irq_startup, (void *) irq, 0, 1); + + return 0; +} + +static void local_rm9k_perfcounter_irq_shutdown(void *args) +{ + unsigned int irq = (unsigned int) args; + unsigned long flags; + + local_irq_save(flags); + mask_rm9k_irq(irq); + local_irq_restore(flags); +} + +static void rm9k_perfcounter_irq_shutdown(unsigned int irq) +{ + on_each_cpu(local_rm9k_perfcounter_irq_shutdown, (void *) irq, 0, 1); +} + + +/* + * While we ack the interrupt interrupts are disabled and thus we don't need + * to deal with concurrency issues. Same for rm9k_cpu_irq_end. + */ +static void rm9k_cpu_irq_ack(unsigned int irq) +{ + /* convert PCI irq numbers to cp0_intmask bit */ + irq = (10 < irq < 15)? 11 : irq; + if (irq == 11) + clear_c0_intcontrol(0x100 << 3); + else + mask_rm9k_irq(irq); +} + +static void rm9k_cpu_irq_end(unsigned int irq) +{ + if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) { + /* convert PCI irq numbers to cp0_intmask bit */ + irq = (10 < irq < 15)? 11 : irq; + if (irq == 11) + set_c0_intcontrol(0x100 << 3); + else + unmask_rm9k_irq(irq); + } +} + +static hw_irq_controller rm9k_irq_controller = { + .typename = "RM9000", + .startup = rm9k_cpu_irq_startup, + .shutdown = rm9k_cpu_irq_shutdown, + .enable = rm9k_cpu_irq_enable, + .disable = rm9k_cpu_irq_disable, + .ack = rm9k_cpu_irq_ack, + .end = rm9k_cpu_irq_end, +}; + +static hw_irq_controller rm9k_perfcounter_irq = { + .typename = "RM9000", + .startup = rm9k_perfcounter_irq_startup, + .shutdown = rm9k_perfcounter_irq_shutdown, + .enable = rm9k_cpu_irq_enable, + .disable = rm9k_cpu_irq_disable, + .ack = rm9k_cpu_irq_ack, + .end = rm9k_cpu_irq_end, +}; + +unsigned int rm9000_perfcount_irq; + +EXPORT_SYMBOL(rm9000_perfcount_irq); + +void __init rm9k_cpu_irq_init(int base) +{ + int i; + + clear_c0_intcontrol(0x0000f000); /* Mask all */ + + for (i = base; i < base + 4; i++) { + irq_desc[i].status = IRQ_DISABLED; + irq_desc[i].action = NULL; + irq_desc[i].depth = 1; + irq_desc[i].handler = &rm9k_irq_controller; + } + + rm9000_perfcount_irq = base + 1; + irq_desc[rm9000_perfcount_irq].handler = &rm9k_perfcounter_irq; + + irq_base = base; +} + + +extern asmlinkage void sequoia_handle_int(void); + +/* + * Handle PCI interrupts. + */ +asmlinkage void pmc_sequoia_pci_isr(int irq, struct pt_regs *regs) +{ + u_int8_t status; + + /* check FPGA intr status register to determine the intr source */ + status = SEQUOIA_FPGA_READ(SEQUOIA_FPGA_INTR_STATUS); + + if (~status & (0x3 << 0)) { /* bus 0, slot 0 */ + do_IRQ(11, regs); + } + if (~status & (0x3 << 2)) { /* bus 0, slot 1 */ + do_IRQ(12, regs); + } + + if (~status & (0x3 << 4)) { /* bus 1, slot 0 */ + do_IRQ(13, regs); + } + if (~status & (0x3 << 6)) { /* bus 1, slot 1 */ + do_IRQ(14, regs); + } +} + +static struct irqaction unused_irq = + { no_action, SA_INTERRUPT, 0, "unused", NULL, NULL }; + +extern unsigned long exception_handlers[32]; + +/* + * Initialize the next level interrupt handler + */ +void __init arch_init_irq(void) +{ + int i; + + clear_c0_status(ST0_IM); + set_c0_status(ST0_IM); + + set_except_vector(0, sequoia_handle_int); + mips_cpu_irq_init(0); + rm7k_cpu_irq_init(8); + rm9k_cpu_irq_init(12); +} + + diff -Naur a/arch/mips/pmc-sierra/sequoia/irq-handler.S b/arch/mips/pmc-sierra/sequoia/irq-handler.S --- a/arch/mips/pmc-sierra/sequoia/irq-handler.S 1969-12-31 16:00:00.000000000 -0800 +++ b/arch/mips/pmc-sierra/sequoia/irq-handler.S 2006-06-22 14:55:16.000000000 -0700 @@ -0,0 +1,99 @@ +/* + * Copyright 2006 PMC-Sierra Inc. + * Author: PMC SIerra Inc (thotakir@xxxxxxxxxxxxxx) + * + * First-level interrupt router for the PMC-Sierra Sequoia board + * + */ + +#define __ASSEMBLY__ +#include <linux/config.h> +#include <asm/asm.h> +#include <asm/mipsregs.h> +#include <asm/addrspace.h> +#include <asm/regdef.h> +#include <asm/stackframe.h> + + .align 5 + NESTED(sequoia_handle_int, PT_SIZE, sp) + SAVE_ALL + CLI + .set at + .set noreorder + mfc0 t0, CP0_CAUSE + mfc0 t2, CP0_STATUS + + and t0, t2 + + andi t1, t0, STATUSF_IP0 /* sw0 software interrupt */ + bnez t1, ll_sw0_irq + andi t1, t0, STATUSF_IP1 /* sw1 software interrupt */ + bnez t1, ll_sw1_irq + /* IP4 reserved for DUART */ + andi t1, t0, STATUSF_IP5 /* XDMA interrupts */ + bnez t1, ll_xdma_irq + /* IP6 reserved for HyperTransport, not supported */ + andi t1, t0, STATUSF_IP7 /* INTB5 hardware line */ + bnez t1, ll_timer_irq /* Timer */ + + nop + nop + + /* Extended interrupts */ + mfc0 t0, CP0_CAUSE + cfc0 t1, CP0_S1_INTCONTROL + + sll t2, t1, 8 + + and t0, t2 + srl t0, t0, 16 + + andi t1, t0, STATUSF_IP10 /* Local Bus */ + bnez t1, ll_lb_irq + andi t1, t0, STATUSF_IP11 /* PCI0 and PCI1 */ + bnez t1, ll_pci_irq + nop /* delay slot */ + .set reorder + + j spurious_interrupt + nop + END(sequoia_handle_int) + + .align 5 + +ll_sw0_irq: + li a0, 0 + move a1, sp + jal do_IRQ + j ret_from_irq + +ll_sw1_irq: + li a0, 1 + move a1, sp + jal do_IRQ + j ret_from_irq + +ll_lb_irq: + li a0, 10 + move a1, sp + jal do_IRQ + j ret_from_irq + +ll_pci_irq: + li a0, 11 + move a1, sp + jal pmc_sequoia_pci_isr + j ret_from_irq + +ll_xdma_irq: + li a0, 5 + move a1, sp + jal do_IRQ + j ret_from_irq + +ll_timer_irq: + li a0, 7 + move a1, sp + jal do_IRQ + j ret_from_irq + diff -Naur a/arch/mips/pmc-sierra/sequoia/Makefile b/arch/mips/pmc-sierra/sequoia/Makefile --- a/arch/mips/pmc-sierra/sequoia/Makefile 1969-12-31 16:00:00.000000000 -0800 +++ b/arch/mips/pmc-sierra/sequoia/Makefile 2006-06-22 11:55:42.000000000 -0700 @@ -0,0 +1,7 @@ +# +# Makefile for the PMC-Sierra Sequoia +# + +obj-y += irq-handler.o irq.o prom.o py-console.o setup.o + + diff -Naur a/arch/mips/pmc-sierra/sequoia/prom.c b/arch/mips/pmc-sierra/sequoia/prom.c --- a/arch/mips/pmc-sierra/sequoia/prom.c 1969-12-31 16:00:00.000000000 -0800 +++ b/arch/mips/pmc-sierra/sequoia/prom.c 2006-06-22 14:57:08.000000000 -0700 @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2006 PMC-Sierra Inc. + * Author: PMC Sierra Inc (thotakir@xxxxxxxxxxxxxx) + */ + +#include <linux/config.h> +#include <linux/init.h> +#include <linux/sched.h> +#include <linux/mm.h> +#include <asm/io.h> +#include <asm/pgtable.h> +#include <asm/processor.h> +#include <asm/reboot.h> +#include <asm/system.h> +#include <linux/delay.h> +#include <linux/smp.h> +#include <asm/bootinfo.h> + +#include <asm/pmc_sequoia.h> + +/* Call Vectors */ +struct callvectors { + int (*open) (char*, int, int); + int (*close) (int); + int (*read) (int, void*, int); + int (*write) (int, void*, int); + off_t (*lseek) (int, off_t, int); + int (*printf) (const char*, ...); + void (*cacheflush) (void); + char* (*gets) (char*); + int (*cpustart) (int, int, int, int); +}; + +struct callvectors* debug_vectors; + +extern unsigned long sequoia_memsize; +extern unsigned long cpu_clock; + +unsigned char titan_ge_mac_addr_base[6] = { + 0x30, 0x30, 0x3a, 0x31, 0x31, 0x31 +}; + +const char *get_system_type(void) +{ + return "PMC-Sierra Sequoia"; +} + +static void prom_cpu0_exit(void) +{ + printk(KERN_NOTICE "SW reset not implemented yet\n"); +} + +/* + * Reset the NVRAM over the local bus + */ +static void prom_exit(void) +{ + prom_cpu0_exit(); +} + +/* + * Get the MAC address from the EEPROM using the I2C protocol + */ +void get_mac_address(char dest[6]) +{ + /* Use the I2C command code in the i2c-sequoia */ +} + +/* + * Halt the system + */ +void prom_halt(void) +{ + printk(KERN_NOTICE "\n** You can safely turn off the power\n"); + while (1) + __asm__(".set\tmips3\n\t" + "wait\n\t" + ".set\tmips0"); +} + +/* + * Init routine which accepts the variables from PMON + */ +void __init prom_init(void) +{ + int i = 0; + int argc = fw_arg0; + char **arg = (char **) fw_arg1; + char **env = (char **) fw_arg2; + struct callvectors *cv = (struct callvectors *) fw_arg3; + + /* Callbacks for halt, restart */ + _machine_restart = (void (*)(char *))prom_exit; + _machine_halt = prom_halt; + _machine_power_off = prom_halt; + + debug_vectors = cv; + arcs_cmdline[0] = '\0'; + + /* Get the boot parameters */ + for (i = 1; i < argc; i++) { + if (strlen(arcs_cmdline) + strlen(arg[i] + 1) >= sizeof(arcs_cmdline)) + break; + + strcat(arcs_cmdline, arg[i]); + strcat(arcs_cmdline, " "); + } + + while (*env) { + if (strncmp("memsize", *env, strlen("memsize")) == 0) { + sequoia_memsize = simple_strtol(*env + strlen("memsize="), + NULL, 10); + + printk("PMON reports memory size %dMB\n", sequoia_memsize); + } + if (strncmp("cpuclock", *env, strlen("cpuclock")) == 0) { + cpu_clock = simple_strtol(*env + strlen("cpuclock="), + NULL, 10); + + printk("cpu_clock set to %d\n", cpu_clock); + } + + env++; + } + + + mips_machgroup = MACH_GROUP_TITAN; + mips_machtype = MACH_TITAN_SEQUOIA; + + get_mac_address(titan_ge_mac_addr_base); + +} + +void __init prom_free_prom_memory(void) +{ +} + +void __init prom_fixup_mem_map(unsigned long start, unsigned long end) +{ +} diff -Naur a/arch/mips/pmc-sierra/sequoia/py-console.c b/arch/mips/pmc-sierra/sequoia/py-console.c --- a/arch/mips/pmc-sierra/sequoia/py-console.c 1969-12-31 16:00:00.000000000 -0800 +++ b/arch/mips/pmc-sierra/sequoia/py-console.c 2006-06-22 11:48:21.000000000 -0700 @@ -0,0 +1,123 @@ +/* + * 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) 2001, 2002, 2004 Ralf Baechle + */ +#include <linux/init.h> +#include <linux/console.h> +#include <linux/kdev_t.h> +#include <linux/major.h> +#include <linux/termios.h> +#include <linux/sched.h> +#include <linux/tty.h> + +#include <linux/serial.h> +#include <linux/serial_core.h> +#include <asm/serial.h> +#include <asm/io.h> + +/* SUPERIO uart register map */ +struct se_uartregs { + union { + volatile u8 rbr; /* read only, DLAB == 0 */ + volatile u8 thr; /* write only, DLAB == 0 */ + volatile u8 dll; /* DLAB == 1 */ + } u1; + union { + volatile u8 ier; /* DLAB == 0 */ + volatile u8 dlm; /* DLAB == 1 */ + } u2; + union { + volatile u8 iir; /* read only */ + volatile u8 fcr; /* write only */ + } u3; + volatile u8 iu_lcr; + volatile u8 iu_mcr; + volatile u8 iu_lsr; + volatile u8 iu_msr; + volatile u8 iu_scr; +} se_uregs_t; + +#define iu_rbr u1.rbr +#define iu_thr u1.thr +#define iu_dll u1.dll +#define iu_ier u2.ier +#define iu_dlm u2.dlm +#define iu_iir u3.iir +#define iu_fcr u3.fcr + +#define IO_BASE_64 0x9000000000000000ULL + +static unsigned char readb_outer_space(unsigned long phys) +{ + unsigned long long vaddr = IO_BASE_64 | phys; + unsigned char res; + unsigned int sr; + + sr = read_c0_status(); + write_c0_status((sr | ST0_KX) & ~ ST0_IE); + __asm__("sll $0, $0, 2\n"); + __asm__("sll $0, $0, 2\n"); + __asm__("sll $0, $0, 2\n"); + __asm__("sll $0, $0, 2\n"); + + __asm__ __volatile__ ( + " .set mips3 \n" + " ld %0, (%0) \n" + " lbu %0, (%0) \n" + " .set mips0 \n" + : "=r" (res) + : "0" (&vaddr)); + + write_c0_status(sr); + __asm__("sll $0, $0, 2\n"); + __asm__("sll $0, $0, 2\n"); + __asm__("sll $0, $0, 2\n"); + __asm__("sll $0, $0, 2\n"); + + return res; +} + +static void writeb_outer_space(unsigned long phys, unsigned char c) +{ + unsigned long long vaddr = IO_BASE_64 | phys; + unsigned long tmp; + unsigned int sr; + + sr = read_c0_status(); + write_c0_status((sr | ST0_KX) & ~ ST0_IE); + __asm__("sll $0, $0, 2\n"); + __asm__("sll $0, $0, 2\n"); + __asm__("sll $0, $0, 2\n"); + __asm__("sll $0, $0, 2\n"); + + __asm__ __volatile__ ( + " .set mips3 \n" + " ld %0, (%1) \n" + " sb %2, (%0) \n" + " .set mips0 \n" + : "=r" (tmp) + : "r" (&vaddr), "r" (c)); + + write_c0_status(sr); + __asm__("sll $0, $0, 2\n"); + __asm__("sll $0, $0, 2\n"); + __asm__("sll $0, $0, 2\n"); + __asm__("sll $0, $0, 2\n"); +} + +void prom_putchar(char c) +{ + unsigned long lsr = 0xfd000008UL + offsetof(struct se_uartregs, iu_lsr); + unsigned long thr = 0xfd000008UL + offsetof(struct se_uartregs, iu_thr); + + while ((readb_outer_space(lsr) & 0x20) == 0); + writeb_outer_space(thr, c); +} + +char __init prom_getchar(void) +{ + return 0; +} diff -Naur a/arch/mips/pmc-sierra/sequoia/setup.c b/arch/mips/pmc-sierra/sequoia/setup.c --- a/arch/mips/pmc-sierra/sequoia/setup.c 1969-12-31 16:00:00.000000000 -0800 +++ b/arch/mips/pmc-sierra/sequoia/setup.c 2006-06-22 14:57:38.000000000 -0700 @@ -0,0 +1,258 @@ +/* + * arch/mip/pmc-sierra/sequoia/setup.c + * + * Copyright (C) 2006 PMC-Sierra Inc. + * Author: PMC Sierra Inc (thotakir@xxxxxxxxxxxxxx) + * + */ + +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/mc146818rtc.h> +#include <linux/mm.h> +#include <linux/swap.h> +#include <linux/ioport.h> +#include <linux/console.h> +#include <linux/sched.h> +#include <linux/interrupt.h> +#include <linux/pci.h> +#include <linux/timex.h> +#include <linux/vmalloc.h> +#include <asm/time.h> +#include <asm/bootinfo.h> +#include <asm/page.h> +#include <asm/bootinfo.h> +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/processor.h> +#include <asm/ptrace.h> +#include <asm/reboot.h> +#include <asm/traps.h> +#include <linux/version.h> +#include <linux/bootmem.h> + +#include <asm/serial.h> +#include <linux/termios.h> +#include <linux/tty.h> +#include <linux/serial.h> +#include <linux/serial_core.h> + +#include <linux/mm.h> + +#include <asm/pmc_sequoia.h> + +#include "setup.h" + +unsigned long titan_ge_base; +unsigned long cpu_clock; +unsigned long sequoia_memsize; + +/* Real Time Clock base */ +#define CONV_BCD_TO_BIN(val) (((val) & 0xf) + (((val) >> 4) * 10)) +#define CONV_BIN_TO_BCD(val) (((val) % 10) + (((val) / 10) << 4)) + +static unsigned long ENTRYLO(unsigned long paddr) +{ + return ((paddr & PAGE_MASK) | + (_PAGE_PRESENT | __READABLE | __WRITEABLE | _PAGE_GLOBAL | + _CACHE_UNCACHED)) >> 6; +} + + +void __init bus_error_init(void) +{ + /* Do nothing */ +} + +unsigned long m48t37y_get_time(void) +{ + unsigned char *rtc_base = SEQUOIA_RTC_BASE_ADDR; + unsigned int year, month, day, hour, min, sec; + + /* Stop the update to the time */ + rtc_base[0x7ff8] = 0x40; + + year = CONV_BCD_TO_BIN(rtc_base[0x7fff]); + year += CONV_BCD_TO_BIN(rtc_base[0x7ff1]) * 100; + + month = CONV_BCD_TO_BIN(rtc_base[0x7ffe]); + day = CONV_BCD_TO_BIN(rtc_base[0x7ffd]); + hour = CONV_BCD_TO_BIN(rtc_base[0x7ffb]); + min = CONV_BCD_TO_BIN(rtc_base[0x7ffa]); + sec = CONV_BCD_TO_BIN(rtc_base[0x7ff9]); + + /* Start the update to the time again */ + rtc_base[0x7ff8] = 0x00; + + return mktime(year, month, day, hour, min, sec); +} + +int m48t37y_set_time(unsigned long sec) +{ + unsigned char *rtc_base = SEQUOIA_RTC_BASE_ADDR; + struct rtc_time tm; + + /* convert to a more useful format -- note months count from 0 */ + to_tm(sec, &tm); + tm.tm_mon += 1; + + /* enable writing */ + rtc_base[0x7ff8] = 0x80; + + /* year */ + rtc_base[0x7fff] = CONV_BIN_TO_BCD(tm.tm_year % 100); + rtc_base[0x7ff1] = CONV_BIN_TO_BCD(tm.tm_year / 100); + + /* month */ + rtc_base[0x7ffe] = CONV_BIN_TO_BCD(tm.tm_mon); + + /* day */ + rtc_base[0x7ffd] = CONV_BIN_TO_BCD(tm.tm_mday); + + /* hour/min/sec */ + rtc_base[0x7ffb] = CONV_BIN_TO_BCD(tm.tm_hour); + rtc_base[0x7ffa] = CONV_BIN_TO_BCD(tm.tm_min); + rtc_base[0x7ff9] = CONV_BIN_TO_BCD(tm.tm_sec); + + /* day of week -- not really used, but let's keep it up-to-date */ + rtc_base[0x7ffc] = CONV_BIN_TO_BCD(tm.tm_wday + 1); + + /* disable writing */ + rtc_base[0x7ff8] = 0x00; + + return 0; +} + +void sequoia_timer_setup(struct irqaction *irq) +{ + setup_irq(7, irq); +} + +void sequoia_time_init(void) +{ + mips_hpt_frequency = cpu_clock / 2; + board_timer_setup = sequoia_timer_setup; +} + +/* workaround for PCI, need to return MIPS_BE_DISCARD */ +int sequoia_be_handler(struct pt_regs *regs, int is_fixup) +{ + int data = regs->cp0_cause & 4; + + /* check for data bus error */ + if ((regs->cp0_cause & 0x7c) == 0x1c) { + unsigned long badvaddr; + unsigned long instruction; + int reg; + + instruction = *(u32 *)regs->cp0_epc; + reg = (instruction >> 21)& 0x1f; + badvaddr = regs->regs[reg] + (instruction & 0xffff); + if (((badvaddr & ~0x3) == SEQUOIA_PCI_0_CONFIG_DATA) + || ((badvaddr & ~0x3) == SEQUOIA_PCI_1_CONFIG_DATA)) { + + /* skip the PCI load instruction */ + regs->cp0_epc += 4; + + /* + * Return all 1's for disallowed accesses + * for a kludgy but adequate simulation of + * master aborts. + */ + reg = (instruction >> 16)& 0x1f; + regs->regs[reg] = 0xffffffff; + return MIPS_BE_DISCARD; + } + } + return MIPS_BE_FATAL; +} + +extern void sequoia_serial_init(void); + +/* No other usable initialization hook than this ... */ +extern void (*late_time_init)(void); + +unsigned long rm9150_pci0_base, rm9150_pci1_base, rm9150_dma_base, sequoia_fpga_base; + +/* + * Common setup before any secondaries are started + */ +#define SEQUOIA_UART_CLK 125000000 + +static void __init py_map_ocd(void) +{ + struct uart_port up; + + unsigned long val = 0; + + add_wired_entry(ENTRYLO(0xff000000), ENTRYLO(0xff000000), 0xff000000, PM_4M); + add_wired_entry(ENTRYLO(0xf8000000), ENTRYLO(0xf8000000), 0xf8000000, PM_4M); + add_wired_entry(ENTRYLO(0xf9000000), ENTRYLO(0xf9000000), 0xf9000000, PM_4M); + titan_ge_base = (unsigned long) ioremap(TITAN_GE_BASE, TITAN_GE_SIZE); + + rm9150_pci0_base = (unsigned long) ioremap(RM9150_PCI0_DCR, RM9150_PCI0_SIZE); + rm9150_pci1_base = (unsigned long) ioremap(RM9150_PCI1_DCR, RM9150_PCI1_SIZE ); + + rm9150_dma_base = (unsigned long) ioremap(RM9150_DMA_DCR, RM9150_DMA_SIZE ); + + sequoia_fpga_base = (unsigned long) ioremap(FPGA_BASE, FPGA_SIZE); + + printk(KERN_INFO "%08x = %08x\n", titan_ge_base, (unsigned long)*(unsigned long*)titan_ge_base); + printk(KERN_INFO "%08x\n", rm9150_pci0_base); + printk(KERN_INFO "%08x\n", rm9150_pci1_base); + printk(KERN_INFO "%08x\n", rm9150_dma_base); + printk(KERN_INFO "%08x\n", sequoia_fpga_base); + dump_tlb_all(); + + /* enable the internal UART */ + printk(KERN_INFO "Internal UART Support for PMC-Sierra Sequoia\n "); + + /* initialize the UART */ + /* Take UART out of reset */ + SEQUOIA_GELA_WRITE(RM9150_UACFG, 3); + + /* UART interrupt disable */ + val = SEQUOIA_GELA_READ(RM9150_CPGIG0ER); + val &= 0; + SEQUOIA_GELA_WRITE(RM9150_CPGIG0ER, val); + + /* + * Register to interrupt zero because we share the interrupt with + * the serial driver which we don't properly support yet. + */ + memset(&up, 0, sizeof(up)); + + up.membase = (unsigned long *) titan_ge_base; + up.irq = SEQUOIA_SERIAL_IRQ; + up.uartclk = SEQUOIA_UART_CLK; + up.regshift = 0; + up.iotype = UPIO_MEM; + up.flags = ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST; + up.line = 0; + + if (early_serial_setup(&up)) + printk(KERN_ERR "Early serial init of port 0 failed\n"); +} + +void __init plat_setup(void) +{ + + unsigned long val = 0; + + printk("PMC-Sierra Sequoia Board Setup \n"); + + +#ifdef CONFIG_MIPS64 + printk("64-bit support \n"); +#else + printk("32-bit support \n"); +#endif + + board_time_init = sequoia_time_init; + late_time_init = py_map_ocd; + board_be_handler = sequoia_be_handler; + + add_memory_region(0x00000000, 0x08000000, BOOT_MEM_RAM); +} + diff -Naur a/arch/mips/pmc-sierra/sequoia/setup.h b/arch/mips/pmc-sierra/sequoia/setup.h --- a/arch/mips/pmc-sierra/sequoia/setup.h 1969-12-31 16:00:00.000000000 -0800 +++ b/arch/mips/pmc-sierra/sequoia/setup.h 2006-06-22 11:48:21.000000000 -0700 @@ -0,0 +1,17 @@ +/* + * Copyright 2006 PMC-Sierra + * Author: PMC Sierra Inc (thotakir@xxxxxxxxxxxxxx) + * + * Board specific definititions for the PMC-Sierra Sequoia + * + */ + +#ifndef __SETUP_H__ +#define __SETUP_H__ + +/* Real Time Clock base */ +#define CONV_BCD_TO_BIN(val) (((val) & 0xf) + (((val) >> 4) * 10)) +#define CONV_BIN_TO_BCD(val) (((val) % 10) + (((val) / 10) << 4)) + +#endif /* __SETUP_H__ */ + diff -Naur a/include/asm-mips/bootinfo.h b/include/asm-mips/bootinfo.h --- a/include/asm-mips/bootinfo.h 2005-07-11 11:28:10.000000000 -0700 +++ b/include/asm-mips/bootinfo.h 2006-06-22 11:48:21.000000000 -0700 @@ -215,6 +215,8 @@ */ #define MACH_GROUP_TITAN 22 /* PMC-Sierra Titan */ #define MACH_TITAN_YOSEMITE 1 /* PMC-Sierra Yosemite */ +#define MACH_TITAN_SEQUOIA 2 /* PMC-Sierra Sequoia */ + #define CL_SIZE COMMAND_LINE_SIZE diff -Naur a/include/asm-mips/mach-sequoia/cpu-feature-overrides.h b/include/asm-mips/mach-sequoia/cpu-feature-overrides.h --- a/include/asm-mips/mach-sequoia/cpu-feature-overrides.h 1969-12-31 16:00:00.000000000 -0800 +++ b/include/asm-mips/mach-sequoia/cpu-feature-overrides.h 2006-06-22 11:48:21.000000000 -0700 @@ -0,0 +1,45 @@ +/* + * 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) 2003, 2004 Ralf Baechle + */ +#ifndef __ASM_MACH_SEQUOIA_CPU_FEATURE_OVERRIDES_H +#define __ASM_MACH_SEQUOIA_CPU_FEATURE_OVERRIDES_H + +/* + * Momentum Jaguar ATX always has the RM9000 processor. + */ +#define cpu_has_watch 1 +#define cpu_has_mips16 0 +#define cpu_has_divec 0 +#define cpu_has_vce 0 +#define cpu_has_cache_cdex_p 0 +#define cpu_has_cache_cdex_s 0 +#define cpu_has_prefetch 1 +#define cpu_has_mcheck 0 +#define cpu_has_ejtag 0 + +#define cpu_has_llsc 1 +#define cpu_has_vtag_icache 0 +#define cpu_has_dc_aliases 0 +#define cpu_has_ic_fills_f_dc 0 +#define cpu_icache_snoops_remote_store 0 + +#define cpu_has_nofpuex 0 +#define cpu_has_64bits 1 + +#define cpu_has_subset_pcaches 0 + +#define cpu_dcache_line_size() 32 +#define cpu_icache_line_size() 32 +#define cpu_scache_line_size() 32 + +/* + * On the RM9000 we need to ensure that I-cache lines being fetches only + * contain valid instructions are funny things will happen. + */ +#define PLAT_TRAMPOLINE_STUFF_LINE 32UL + +#endif /* __ASM_MACH_SEQUOIA_CPU_FEATURE_OVERRIDES_H */ diff -Naur a/include/asm-mips/pmc_sequoia.h b/include/asm-mips/pmc_sequoia.h --- a/include/asm-mips/pmc_sequoia.h 1969-12-31 16:00:00.000000000 -0800 +++ b/include/asm-mips/pmc_sequoia.h 2006-06-22 14:58:46.000000000 -0700 @@ -0,0 +1,296 @@ +/* + * Copyright 2006 PMC-Sierra + * Author: PMC Sierra Inc (thotakir@xxxxxxxxxxxxxx) + * + * Board specific definititions for the PMC-Sierra Sequoia (MSP85x0) + * + */ + +#ifndef __PMC_SEQUOIA_H__ +#define __PMC_SEQUOIA_H__ + +#include <linux/config.h> +#include <asm/addrspace.h> /* for KSEG1ADDR() */ +#include <asm/byteorder.h> /* for cpu_to_le32() */ +#include <asm/io.h> /* for ioswab */ + +/* The base address of the system */ +extern unsigned long sequoia_base; + +extern unsigned long rm9150_pci0_base; +extern unsigned long rm9150_pci1_base; +extern unsigned long rm9150_dma_base; +extern unsigned long titan_ge_base; +extern unsigned long sequoia_fpga_base; + +/* FDB ports base addresses , from PMON */ +#define BOOT_BASE 0xfc000000 +#define FLASH_BASE 0xfc000000 +#define RTC_BASE 0xfc200000 +#define FPGA_BASE (RTC_BASE + 0x10000) +#define FPGA_SIZE 0x10000 +#define RM9150_PCI0_DCR 0xff000000 +#define RM9150_PCI1_DCR 0xff010000 +#define RM9150_DDR_DCR 0xff020000 +#define RM9150_FDB_DCR 0xff030000 +#define RM9150_DMA_DCR 0xff040000 +#define RM9150_OCM_DCR 0xff050000 +#define RM9150_LOCALBUS_DCR 0xff070000 +#define RM9150_GE_DCR 0xff080000 + +#define RM9150_PCI0_SIZE 0x10000 +#define RM9150_PCI1_SIZE 0x10000 +#define RM9150_DMA_SIZE 0x10000 +#define RM9150_LOCALBUS_SIZE 0x10000 + +/* FPGA interrupt status and mask registers */ +#define SEQUOIA_FPGA_INTR_STATUS (0x6) +#define SEQUOIA_FPGA_INTR_MASK (0x8) + +#define SEQUOIA_FPGA_READ(reg) (*(volatile u8 *)(sequoia_fpga_base + (reg))) +#define SEQUOIA_FPGA_WRITE(reg, val) \ + do { *(volatile u8 *)(sequoia_fpga_base + (reg)) = (val); } while (0) + +/* RTC and NVRAM Base */ +#define SEQUOIA_RTC_BASE_ADDR RTC_BASE +#define SEQUOIA_NVRAM_BASE_ADDR RTC_BASE + +/* + * RM9150 on-chip RAM + */ +#define RM9150_SRAM_BASE 0xfb000000 +#define RM9150_SRAM_SIZE 0x00008000 /* 32 KB */ + +/* low-speed I/O registers base */ +#define SEQUOIA_GELA_BASE RM9150_GE_DCR + + + +#define TITAN_GE_BASE (RM9150_GE_DCR) +#define TITAN_GE_SIZE 0x10000UL + +#define TITAN_GE_WRITE(offset, data) \ + *(volatile u32 *)(titan_ge_base + (offset)) = (data) + +#define TITAN_GE_READ(offset) *(volatile u32 *)(titan_ge_base + (offset)) + +/* UART definitions, offset from GELA */ +#define RM9150_UACFG (0x500) +#define RM9150_UAINTS (0x504) + +/* CPGIG0SR: UART interrupt status register, p. 334 */ +#define RM9150_CPGIG0SR (0x0024) +#define RM9150_CPGIG0SR_UINT 0x18000000 + +/* CPGIG0SR: UART interrupt enable register, p. 346 */ +#define RM9150_CPGIG0ER (0x0034) +#define RM9150_CPGIG0ER_UINTE 0x18000000 + +/* UART Interrupt Vector Message register, p. 355 */ +#define RM9150_UART_INTVEC (0x0054) +#define RM9150_UART0_INTVEC 0x40 +#define RM9150_UART1_INTVEC 0x41 + +/* Interrupt Set Message Resend register, p. 364 */ +#define RM9150_CPINTSMR1R (0x0078) +#define RM9150_CPINTSMR1R_UART0 0x0400 +#define RM9150_CPINTSMR1R_UART1 0x0800 + +/* CPIF2 Interrupt Set Message Resend Mode register, p. 368 */ +#define RM9150_CPINTSMR (0x007c) +#define RM9150_CPINTSMR_SWEOIACK_MODE 0x01 +#define RM9150_CPINTSMR_TX_ACK_MOD 0x08 +#define RM9150_CPINTSMR_RX_ACK_MOD 0x10 + +/* GPIO registers for CF/PCMCIA */ +#define RM9150_CPGPISR1 0xA4 +#define RM9150_CPGPIMR1 0xA8 + +#define SEQUOIA_GELA_READ(reg) (*(volatile unsigned int *)(titan_ge_base + (reg))) +#define SEQUOIA_GELA_WRITE(reg, val) \ + do { *(volatile unsigned int *)(titan_ge_base + (reg)) = (val); } while (0) + +#define RM9150_GDMA_BASE RM9150_DMA_DCR +#define RM9150_GCIC_BASE (RM9150_GDMA_BASE + 0x8000) + +#define RM9150_GCIC_INTMSG (0x10) +#define RM9150_GCIC_INT0_STATUS (0x30) +#define RM9150_GCIC_INT0_MASK (0x34) +#define RM9150_GCIC_INT0_SET (0x38) +#define RM9150_GCIC_INT0_CLEAR (0x3c) +#define RM9150_GCIC_INT1_STATUS (0x40) +#define RM9150_GCIC_INT1_MASK (0x44) +#define RM9150_GCIC_INT1_SET (0x48) +#define RM9150_GCIC_INT1_CLEAR (0x4c) +#define RM9150_GCIC_INT2_STATUS (0x50) +#define RM9150_GCIC_INT2_MASK (0x54) +#define RM9150_GCIC_INT2_SET (0x58) +#define RM9150_GCIC_INT2_CLEAR (0x5c) +#define RM9150_GCIC_INT3_STATUS (0x60) +#define RM9150_GCIC_INT3_MASK (0x64) +#define RM9150_GCIC_INT3_SET (0x68) +#define RM9150_GCIC_INT3_CLEAR (0x6c) +#define RM9150_GCIC_INT4_STATUS (0x70) +#define RM9150_GCIC_INT4_MASK (0x74) +#define RM9150_GCIC_INT4_SET (0x78) +#define RM9150_GCIC_INT4_CLEAR (0x7c) +#define RM9150_GCIC_INT5_STATUS (0x80) +#define RM9150_GCIC_INT5_MASK (0x84) +#define RM9150_GCIC_INT5_SET (0x88) +#define RM9150_GCIC_INT5_CLEAR (0x8c) +#define RM9150_GCIC_INT6_STATUS (0x90) +#define RM9150_GCIC_INT6_MASK (0x94) +#define RM9150_GCIC_INT6_SET (0x98) +#define RM9150_GCIC_INT6_CLEAR (0x9c) +#define RM9150_GCIC_INT7_STATUS (0xa0) +#define RM9150_GCIC_INT7_MASK (0xa4) +#define RM9150_GCIC_INT7_SET (0xa8) +#define RM9150_GCIC_INT7_CLEAR (0xac) + +#define SEQUOIA_CICA_READ(reg) (*(volatile unsigned int *)(rm9150_dma_base + 0x8000 + (reg))) +#define SEQUOIA_CICA_WRITE(reg, val) \ + do { *(volatile unsigned int *)(rm9150_dma_base + 0x8000 + (reg)) = (val); } while (0) + + +/* PCI */ + +/* + * PCI configuration registers + * pmon2000/src/Targets/Sequoia/compile/SEQUOIA-EB/machine/rm9150_pci.h + */ +#define RM9150_PCI_GDI_IDENT 0x0000 +#define RM9150_PCI_IAM_CONFIG_STATUS 0x0004 +#define RM9150_PCI_CONFIG_ADDR 0x0010 +#define RM9150_PCI_CONFIG_DATA 0x0014 +#define RM9150_PCI_CONFIG_STATUS 0x0018 +#define RM9150_PCI_GDI_BAR0 0x001c +#define RM9150_PCI_GDI_BAR0_ATTRIBUTES 0x0020 +#define RM9150_PCI_GDI_BAR1 0x0024 +#define RM9150_PCI_GDI_BAR1_ATTRIBUTES 0x0028 +#define RM9150_PCI_GDI_BAR2 0x002c +#define RM9150_PCI_GDI_BAR2_ATTRIBUTES 0x0030 +#define RM9150_PCI_GDI_BAR3 0x0034 +#define RM9150_PCI_GDI_BAR3_ATTRIBUTES 0x0038 +#define RM9150_PCI_GDI_BAR4 0x003c +#define RM9150_PCI_GDI_BAR4_ATTRIBUTES 0x0040 +#define RM9150_PCI_GDI_BAR5 0x0044 +#define RM9150_PCI_GDI_BAR5_ATTRIBUTES 0x0048 +#define RM9150_PCI_MASTER_GDI_VIRT_IOBASE 0x004c +#define RM9150_PCI_MASTER_GDI_VIRT_IOMASK 0x0050 +#define RM9150_PCI_MASTER_GDI_VIRT_PREFETCH_BASE 0x0054 +#define RM9150_PCI_MASTER_GDI_VIRT_PREFETCH_SIZE 0x0058 +#define RM9150_PCI_MASTER_WRITE_REQ_DATA_SWAP 0x0080 +#define RM9150_PCI_MASTER_READ_RESP_DATA_SWAP 0x0084 +#define RM9150_PCI_RESET 0x008c +#define RM9150_PCI_RESPONSE_ERROR_MASK 0x0090 +#define RM9150_PCI_TRANSACTION_COMBINING 0x0094 +#define RM9150_PCI_ECC_STATUS 0x00a8 +#define RM9150_PCI_ECC_ERROR_INJECTION 0x00ac +#define RM9150_PCI_DEVICE_VENDOR_ID 0x0100 +#define RM9150_PCI_COMMAND_STATUS 0x0104 +#define RM9150_PCI_CLASS_CODE_REV_ID 0x0108 +#define RM9150_PCI_BIST_HEADER_TYPE 0x010c +#define RM9150_PCI_TARGET_BAR0 0x0110 +#define RM9150_PCI_TARGET_BAR1 0x0114 +#define RM9150_PCI_TARGET_BAR2 0x0118 +#define RM9150_PCI_TARGET_BAR3 0x011c +#define RM9150_PCI_TARGET_BAR4 0x0120 +#define RM9150_PCI_TARGET_BAR5 0x0124 +#define RM9150_PCI_SUBSYSTEM_DEVICE_VENDOR_ID 0x012c +#define RM9150_PCI_EXPANSION_ROM_BASE_ADDR 0x0130 +#define RM9150_PCI_CAPABILITIES_POINTER 0x0134 +#define RM9150_PCI_INTERRUPT_LINE 0x013c +#define RM9150_PCI_CONFIG_STATUS_1 0x0140 +#define RM9150_PCI_TARGET_DELAYED_TRANSACTIONS 0x0148 +#define RM9150_PCI_CONFIG_STATUS_2 0x014c +#define RM9150_PCI_MASTER_DEFERRED_TRANSACTIONS 0x0148 +#define RM9150_PCI_CONFIG_STATUS_3 0x0158 +#define RM9150_PCI_CONFIGURATION_HOLD_0 0x0200 +#define RM9150_PCI_CONFIGURATION_HOLD_1 0x0204 +#define RM9150_PCI_CONFIGURATION_HOLD_2 0x0208 +#define RM9150_PCI_CONFIGURATION_HOLD_3 0x020c +#define RM9150_PCI_CONFIGURATION_HOLD_4 0x0210 +#define RM9150_PCI_CONFIGURATION_HOLD_5 0x0214 +#define RM9150_PCI_CONFIGURATION_HOLD_6 0x0218 +#define RM9150_PCI_CONFIGURATION_HOLD_7 0x021c +#define RM9150_PCI_CONFIGURATION_HOLD_8 0x0220 +#define RM9150_PCI_CONFIGURATION_HOLD_9 0x0224 +#define RM9150_PCI_CONFIGURATION_HOLD_10 0x0228 +#define RM9150_PCI_CONFIGURATION_HOLD_11 0x022c +#define RM9150_PCI_CONFIGURATION_HOLD_12 0x0230 +#define RM9150_PCI_CONFIGURATION_HOLD_13 0x0234 +#define RM9150_PCI_INTERRUPT_MSG_HANDSHAKE 0x0238 +#define RM9150_PCI_ERROR_STATUS_FAULT_INTERRUPT 0x0254 +#define RM9150_PCI_SERR_CAUSE_ENABLE 0x0258 +#define RM9150_PCI_FAULT_INTERRUPT_ENABLE 0x025c +#define RM9150_PCI_ERROR_ADDRESS_EVENT 0x0260 +#define RM9150_PCI_ERROR_ADDRESS 0x0264 +#define RM9150_PCI_GDI_DIAGNOSTIC_ERRORS 0x0268 + +/* + * PCI Bus 0 + */ +#define SEQUOIA_PCI0_MEM_BASE 0xe0000000 +#define SEQUOIA_PCI0_MEM_SIZE 0x08000000 +#define SEQUOIA_PCI0_IO_BASE 0xf8000000 +#define SEQUOIA_PCI0_IO_SIZE 0x01000000 + +/* + * PCI Bus 1 + */ +#define SEQUOIA_PCI1_MEM_BASE 0xe8000000 +#define SEQUOIA_PCI1_MEM_SIZE 0x08000000 +#define SEQUOIA_PCI1_IO_BASE 0xf9000000 +#define SEQUOIA_PCI1_IO_SIZE 0x01000000 + +#define SEQUOIA_PCI_MEM_BASE 0xe0000000 +#define SEQUOIA_PCI_MEM_SIZE 0x18000000 +#define SEQUOIA_PCI_IO_BASE 0xf8000000 +#define SEQUOIA_PCI_IO_SIZE 0x02000000 + +/* + * PCI 0 specific defines + */ +#define SEQUOIA_PCI0_BASE RM9150_PCI0_DCR +#define SEQUOIA_PCI_0_CONFIG_ADDRESS (RM9150_PCI0_DCR + RM9150_PCI_CONFIG_ADDR) +#define SEQUOIA_PCI_0_CONFIG_DATA (rm9150_pci0_base + RM9150_PCI_CONFIG_DATA) + +/* + * PCI 1 specific defines + */ +#define SEQUOIA_PCI1_BASE RM9150_PCI1_DCR +#define SEQUOIA_PCI_1_CONFIG_ADDRESS (RM9150_PCI1_DCR + RM9150_PCI_CONFIG_ADDR) +#define SEQUOIA_PCI_1_CONFIG_DATA (rm9150_pci1_base + RM9150_PCI_CONFIG_DATA) + +#define SEQUOIA_PCI0_WRITE(ofs, data) \ + do { *(volatile u32 *)( rm9150_pci0_base + (ofs)) = (data); } while(0) +#define SEQUOIA_PCI0_READ(ofs) \ + *(volatile u32 *)(rm9150_pci0_base +(ofs)) + +#define SEQUOIA_PCI0_WRITE_16(ofs, data) \ + do { *(volatile u16 *)(rm9150_pci0_base + (ofs)) = (data); } while(0) +#define SEQUOIA_PCI0_READ_16(ofs) \ + *(volatile u16 *)(rm9150_pci0_base +(ofs)) + +#define SEQUOIA_PCI0_WRITE_8(ofs, data) \ + do { *(volatile u8 *)(rm9150_pci0_base + (ofs)) = (data); } while(0) +#define SEQUOIA_PCI0_READ_8(ofs) \ + *(volatile u8 *)(rm9150_pci0_base +(ofs)) + + +#define SEQUOIA_PCI1_WRITE(ofs, data) \ + do { *(volatile u32 *)(rm9150_pci1_base + (ofs)) = (data); } while(0) +#define SEQUOIA_PCI1_READ(ofs) \ + *(volatile u32 *)(rm9150_pci1_base +(ofs)) + +#define SEQUOIA_PCI1_WRITE_16(ofs, data) \ + do { *(volatile u16 *)(rm9150_pci1_base + (ofs)) = (data); } while(0) +#define SEQUOIA_PCI1_READ_16(ofs) \ + *(volatile u16 *)(rm9150_pci1_base +(ofs)) + +#define SEQUOIA_PCI1_WRITE_8(ofs, data) \ + do { *(volatile u8 *)(rm9150_pci1_base + (ofs)) = (data); } while(0) +#define SEQUOIA_PCI1_READ_8(ofs) \ + *(volatile u8 *)(rm9150_pci1_base +(ofs)) + +#endif