diff options
author | André Fabian Silva Delgado <emulatorman@parabola.nu> | 2015-08-05 17:04:01 -0300 |
---|---|---|
committer | André Fabian Silva Delgado <emulatorman@parabola.nu> | 2015-08-05 17:04:01 -0300 |
commit | 57f0f512b273f60d52568b8c6b77e17f5636edc0 (patch) | |
tree | 5e910f0e82173f4ef4f51111366a3f1299037a7b /arch/mips/mti-malta |
Initial import
Diffstat (limited to 'arch/mips/mti-malta')
-rw-r--r-- | arch/mips/mti-malta/Makefile | 13 | ||||
-rw-r--r-- | arch/mips/mti-malta/Platform | 11 | ||||
-rw-r--r-- | arch/mips/mti-malta/malta-amon.c | 88 | ||||
-rw-r--r-- | arch/mips/mti-malta/malta-display.c | 56 | ||||
-rw-r--r-- | arch/mips/mti-malta/malta-init.c | 305 | ||||
-rw-r--r-- | arch/mips/mti-malta/malta-int.c | 503 | ||||
-rw-r--r-- | arch/mips/mti-malta/malta-memory.c | 211 | ||||
-rw-r--r-- | arch/mips/mti-malta/malta-platform.c | 147 | ||||
-rw-r--r-- | arch/mips/mti-malta/malta-pm.c | 96 | ||||
-rw-r--r-- | arch/mips/mti-malta/malta-reset.c | 47 | ||||
-rw-r--r-- | arch/mips/mti-malta/malta-setup.c | 289 | ||||
-rw-r--r-- | arch/mips/mti-malta/malta-time.c | 211 |
12 files changed, 1977 insertions, 0 deletions
diff --git a/arch/mips/mti-malta/Makefile b/arch/mips/mti-malta/Makefile new file mode 100644 index 000000000..6510ace27 --- /dev/null +++ b/arch/mips/mti-malta/Makefile @@ -0,0 +1,13 @@ +# +# Carsten Langgaard, carstenl@mips.com +# Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved. +# +# Copyright (C) 2008 Wind River Systems, Inc. +# written by Ralf Baechle <ralf@linux-mips.org> +# +obj-y := malta-display.o malta-init.o \ + malta-int.o malta-memory.o malta-platform.o \ + malta-reset.o malta-setup.o malta-time.o + +obj-$(CONFIG_MIPS_CMP) += malta-amon.o +obj-$(CONFIG_MIPS_MALTA_PM) += malta-pm.o diff --git a/arch/mips/mti-malta/Platform b/arch/mips/mti-malta/Platform new file mode 100644 index 000000000..2cc72c9b3 --- /dev/null +++ b/arch/mips/mti-malta/Platform @@ -0,0 +1,11 @@ +# +# MIPS Malta board +# +platform-$(CONFIG_MIPS_MALTA) += mti-malta/ +cflags-$(CONFIG_MIPS_MALTA) += -I$(srctree)/arch/mips/include/asm/mach-malta +ifdef CONFIG_KVM_GUEST + load-$(CONFIG_MIPS_MALTA) += 0x0000000040100000 +else + load-$(CONFIG_MIPS_MALTA) += 0xffffffff80100000 +endif +all-$(CONFIG_MIPS_MALTA) := $(COMPRESSION_FNAME).bin diff --git a/arch/mips/mti-malta/malta-amon.c b/arch/mips/mti-malta/malta-amon.c new file mode 100644 index 000000000..84ac523b0 --- /dev/null +++ b/arch/mips/mti-malta/malta-amon.c @@ -0,0 +1,88 @@ +/* + * 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) 2007 MIPS Technologies, Inc. All rights reserved. + * Copyright (C) 2013 Imagination Technologies Ltd. + * + * Arbitrary Monitor Interface + */ +#include <linux/kernel.h> +#include <linux/smp.h> + +#include <asm/addrspace.h> +#include <asm/mipsmtregs.h> +#include <asm/mips-boards/launch.h> +#include <asm/vpe.h> + +int amon_cpu_avail(int cpu) +{ + struct cpulaunch *launch = (struct cpulaunch *)CKSEG0ADDR(CPULAUNCH); + + if (cpu < 0 || cpu >= NCPULAUNCH) { + pr_debug("avail: cpu%d is out of range\n", cpu); + return 0; + } + + launch += cpu; + if (!(launch->flags & LAUNCH_FREADY)) { + pr_debug("avail: cpu%d is not ready\n", cpu); + return 0; + } + if (launch->flags & (LAUNCH_FGO|LAUNCH_FGONE)) { + pr_debug("avail: too late.. cpu%d is already gone\n", cpu); + return 0; + } + + return 1; +} + +int amon_cpu_start(int cpu, + unsigned long pc, unsigned long sp, + unsigned long gp, unsigned long a0) +{ + volatile struct cpulaunch *launch = + (struct cpulaunch *)CKSEG0ADDR(CPULAUNCH); + + if (!amon_cpu_avail(cpu)) + return -1; + if (cpu == smp_processor_id()) { + pr_debug("launch: I am cpu%d!\n", cpu); + return -1; + } + launch += cpu; + + pr_debug("launch: starting cpu%d\n", cpu); + + launch->pc = pc; + launch->gp = gp; + launch->sp = sp; + launch->a0 = a0; + + smp_wmb(); /* Target must see parameters before go */ + launch->flags |= LAUNCH_FGO; + smp_wmb(); /* Target must see go before we poll */ + + while ((launch->flags & LAUNCH_FGONE) == 0) + ; + smp_rmb(); /* Target will be updating flags soon */ + pr_debug("launch: cpu%d gone!\n", cpu); + + return 0; +} + +#ifdef CONFIG_MIPS_VPE_LOADER_CMP +int vpe_run(struct vpe *v) +{ + struct vpe_notifications *n; + + if (amon_cpu_start(aprp_cpu_index(), v->__start, 0, 0, 0) < 0) + return -1; + + list_for_each_entry(n, &v->notify, list) + n->start(VPE_MODULE_MINOR); + + return 0; +} +#endif diff --git a/arch/mips/mti-malta/malta-display.c b/arch/mips/mti-malta/malta-display.c new file mode 100644 index 000000000..d4f807191 --- /dev/null +++ b/arch/mips/mti-malta/malta-display.c @@ -0,0 +1,56 @@ +/* + * 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. + * + * Display routines for display messages in MIPS boards ascii display. + * + * Copyright (C) 1999,2000,2012 MIPS Technologies, Inc. + * All rights reserved. + * Authors: Carsten Langgaard <carstenl@mips.com> + * Steven J. Hill <sjhill@mips.com> + */ +#include <linux/compiler.h> +#include <linux/timer.h> +#include <linux/io.h> + +#include <asm/mips-boards/generic.h> + +extern const char display_string[]; +static unsigned int display_count; +static unsigned int max_display_count; + +void mips_display_message(const char *str) +{ + static unsigned int __iomem *display = NULL; + int i; + + if (unlikely(display == NULL)) + display = ioremap(ASCII_DISPLAY_POS_BASE, 16*sizeof(int)); + + for (i = 0; i <= 14; i += 2) { + if (*str) + __raw_writel(*str++, display + i); + else + __raw_writel(' ', display + i); + } +} + +static void scroll_display_message(unsigned long data); +static DEFINE_TIMER(mips_scroll_timer, scroll_display_message, HZ, 0); + +static void scroll_display_message(unsigned long data) +{ + mips_display_message(&display_string[display_count++]); + if (display_count == max_display_count) + display_count = 0; + + mod_timer(&mips_scroll_timer, jiffies + HZ); +} + +void mips_scroll_message(void) +{ + del_timer_sync(&mips_scroll_timer); + max_display_count = strlen(display_string) + 1 - 8; + mod_timer(&mips_scroll_timer, jiffies + 1); +} diff --git a/arch/mips/mti-malta/malta-init.c b/arch/mips/mti-malta/malta-init.c new file mode 100644 index 000000000..cec3e187c --- /dev/null +++ b/arch/mips/mti-malta/malta-init.c @@ -0,0 +1,305 @@ +/* + * 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. + * + * PROM library initialisation code. + * + * Copyright (C) 1999,2000,2004,2005,2012 MIPS Technologies, Inc. + * All rights reserved. + * Authors: Carsten Langgaard <carstenl@mips.com> + * Maciej W. Rozycki <macro@mips.com> + * Steven J. Hill <sjhill@mips.com> + */ +#include <linux/init.h> +#include <linux/string.h> +#include <linux/kernel.h> +#include <linux/serial_core.h> + +#include <asm/cacheflush.h> +#include <asm/smp-ops.h> +#include <asm/traps.h> +#include <asm/fw/fw.h> +#include <asm/mips-cm.h> +#include <asm/mips-cpc.h> +#include <asm/mips-boards/generic.h> +#include <asm/mips-boards/malta.h> + +static int mips_revision_corid; +int mips_revision_sconid; + +/* 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; + +#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; + + s = fw_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'; + + if ((strstr(fw_getcmdline(), "earlycon=")) == NULL) { + sprintf(console_string, "uart8250,io,0x3f8,%d%c%c", baud, + parity, bits); + setup_earlycon(console_string); + } + + if ((strstr(fw_getcmdline(), "console=")) == NULL) { + sprintf(console_string, " console=ttyS0,%d%c%c%c", baud, + parity, bits, flow); + strcat(fw_getcmdline(), console_string); + pr_info("Config serial console:%s\n", console_string); + } +} +#endif + +static void __init mips_nmi_setup(void) +{ + void *base; + extern char except_vec_nmi; + + base = cpu_has_veic ? + (void *)(CAC_BASE + 0xa80) : + (void *)(CAC_BASE + 0x380); + memcpy(base, &except_vec_nmi, 0x80); + flush_icache_range((unsigned long)base, (unsigned long)base + 0x80); +} + +static void __init mips_ejtag_setup(void) +{ + void *base; + extern char except_vec_ejtag_debug; + + base = cpu_has_veic ? + (void *)(CAC_BASE + 0xa00) : + (void *)(CAC_BASE + 0x300); + memcpy(base, &except_vec_ejtag_debug, 0x80); + flush_icache_range((unsigned long)base, (unsigned long)base + 0x80); +} + +phys_addr_t mips_cpc_default_phys_base(void) +{ + return CPC_BASE_ADDR; +} + +void __init prom_init(void) +{ + mips_display_message("LINUX"); + + /* + * 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; + } + + mips_revision_sconid = MIPS_REVISION_SCONID; + if (mips_revision_sconid == MIPS_REVISION_SCON_OTHER) { + 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: + mips_revision_sconid = MIPS_REVISION_SCON_GT64120; + break; + case MIPS_REVISION_CORID_CORE_EMUL_BON: + case MIPS_REVISION_CORID_BONITO64: + case MIPS_REVISION_CORID_CORE_20K: + mips_revision_sconid = MIPS_REVISION_SCON_BONITO; + break; + case MIPS_REVISION_CORID_CORE_MSC: + case MIPS_REVISION_CORID_CORE_FPGA2: + case MIPS_REVISION_CORID_CORE_24K: + /* + * SOCit/ROCit support is essentially identical + * but make an attempt to distinguish them + */ + mips_revision_sconid = MIPS_REVISION_SCON_SOCIT; + break; + case MIPS_REVISION_CORID_CORE_FPGA3: + case MIPS_REVISION_CORID_CORE_FPGA4: + case MIPS_REVISION_CORID_CORE_FPGA5: + case MIPS_REVISION_CORID_CORE_EMUL_MSC: + default: + /* See above */ + mips_revision_sconid = MIPS_REVISION_SCON_ROCIT; + break; + } + } + + switch (mips_revision_sconid) { + u32 start, map, mask, data; + + case MIPS_REVISION_SCON_GT64120: + /* + * 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 + /* Fix up PCI I/O mapping if necessary (for Atlas). */ + start = GT_READ(GT_PCI0IOLD_OFS); + map = GT_READ(GT_PCI0IOREMAP_OFS); + if ((start & map) != 0) { + map &= ~start; + GT_WRITE(GT_PCI0IOREMAP_OFS, map); + } + + set_io_port_base(MALTA_GT_PORT_BASE); + break; + + case MIPS_REVISION_SCON_BONITO: + _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 + + set_io_port_base(MALTA_BONITO_PORT_BASE); + break; + + case MIPS_REVISION_SCON_SOCIT: + case MIPS_REVISION_SCON_ROCIT: + _pcictrl_msc = (unsigned long)ioremap(MIPS_MSC01_PCI_REG_BASE, 0x2000); +mips_pci_controller: + mb(); + MSC_READ(MSC01_PCI_CFG, data); + MSC_WRITE(MSC01_PCI_CFG, data & ~MSC01_PCI_CFG_EN_BIT); + wmb(); + + /* Fix up lane swapping. */ +#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 +#ifndef CONFIG_EVA + /* Fix up target memory mapping. */ + MSC_READ(MSC01_PCI_BAR0, mask); + MSC_WRITE(MSC01_PCI_P2SCMSKL, mask & MSC01_PCI_BAR0_SIZE_MSK); +#else + /* + * Setup the Malta max (2GB) memory for PCI DMA in host bridge + * in transparent addressing mode, starting from 0x80000000. + */ + mask = PHYS_OFFSET | (1<<3); + MSC_WRITE(MSC01_PCI_BAR0, mask); + + mask = PHYS_OFFSET; + MSC_WRITE(MSC01_PCI_HEAD4, mask); + MSC_WRITE(MSC01_PCI_P2SCMSKL, mask); + MSC_WRITE(MSC01_PCI_P2SCMAPL, mask); +#endif + /* Don't handle target retries indefinitely. */ + if ((data & MSC01_PCI_CFG_MAXRTRY_MSK) == + MSC01_PCI_CFG_MAXRTRY_MSK) + data = (data & ~(MSC01_PCI_CFG_MAXRTRY_MSK << + MSC01_PCI_CFG_MAXRTRY_SHF)) | + ((MSC01_PCI_CFG_MAXRTRY_MSK - 1) << + MSC01_PCI_CFG_MAXRTRY_SHF); + + wmb(); + MSC_WRITE(MSC01_PCI_CFG, data); + mb(); + + set_io_port_base(MALTA_MSC_PORT_BASE); + break; + + case MIPS_REVISION_SCON_SOCITSC: + case MIPS_REVISION_SCON_SOCITSCP: + _pcictrl_msc = (unsigned long)ioremap(MIPS_SOCITSC_PCI_REG_BASE, 0x2000); + goto mips_pci_controller; + + default: + /* Unknown system controller */ + mips_display_message("SC Error"); + while (1); /* We die here... */ + } + board_nmi_handler_setup = mips_nmi_setup; + board_ejtag_handler_setup = mips_ejtag_setup; + + fw_init_cmdline(); + fw_meminit(); +#ifdef CONFIG_SERIAL_8250_CONSOLE + console_config(); +#endif + /* Early detection of CMP support */ + mips_cm_probe(); + mips_cpc_probe(); + + if (!register_cps_smp_ops()) + return; + if (!register_cmp_smp_ops()) + return; + if (!register_vsmp_smp_ops()) + return; +} diff --git a/arch/mips/mti-malta/malta-int.c b/arch/mips/mti-malta/malta-int.c new file mode 100644 index 000000000..d1392f8f5 --- /dev/null +++ b/arch/mips/mti-malta/malta-int.c @@ -0,0 +1,503 @@ +/* + * 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. + * + * Carsten Langgaard, carstenl@mips.com + * Copyright (C) 2000, 2001, 2004 MIPS Technologies, Inc. + * Copyright (C) 2001 Ralf Baechle + * Copyright (C) 2013 Imagination Technologies Ltd. + * + * Routines for generic manipulation of the interrupts found on the MIPS + * Malta board. The interrupt controller is located in the South Bridge + * a PIIX4 device with two internal 82C95 interrupt controllers. + */ +#include <linux/init.h> +#include <linux/irq.h> +#include <linux/sched.h> +#include <linux/smp.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/irqchip/mips-gic.h> +#include <linux/kernel_stat.h> +#include <linux/kernel.h> +#include <linux/random.h> + +#include <asm/traps.h> +#include <asm/i8259.h> +#include <asm/irq_cpu.h> +#include <asm/irq_regs.h> +#include <asm/mips-cm.h> +#include <asm/mips-boards/malta.h> +#include <asm/mips-boards/maltaint.h> +#include <asm/gt64120.h> +#include <asm/mips-boards/generic.h> +#include <asm/mips-boards/msc01_pci.h> +#include <asm/msc01_ic.h> +#include <asm/setup.h> +#include <asm/rtlx.h> + +static void __iomem *_msc01_biu_base; + +static DEFINE_RAW_SPINLOCK(mips_irq_lock); + +static inline int mips_pcibios_iack(void) +{ + int irq; + + /* + * Determine highest priority pending interrupt by performing + * a PCI Interrupt Acknowledge cycle. + */ + switch (mips_revision_sconid) { + case MIPS_REVISION_SCON_SOCIT: + case MIPS_REVISION_SCON_ROCIT: + case MIPS_REVISION_SCON_SOCITSC: + case MIPS_REVISION_SCON_SOCITSCP: + MSC_READ(MSC01_PCI_IACK, irq); + irq &= 0xff; + break; + case MIPS_REVISION_SCON_GT64120: + irq = GT_READ(GT_PCI0_IACK_OFS); + irq &= 0xff; + break; + case MIPS_REVISION_SCON_BONITO: + /* The following will generate a PCI IACK cycle on the + * Bonito controller. It's a little bit kludgy, but it + * was the easiest way to implement it in hardware at + * the given time. + */ + BONITO_PCIMAP_CFG = 0x20000; + + /* Flush Bonito register block */ + (void) BONITO_PCIMAP_CFG; + iob(); /* sync */ + + irq = __raw_readl((u32 *)_pcictrl_bonito_pcicfg); + iob(); /* sync */ + irq &= 0xff; + BONITO_PCIMAP_CFG = 0; + break; + default: + pr_emerg("Unknown system controller.\n"); + return -1; + } + return irq; +} + +static inline int get_int(void) +{ + unsigned long flags; + int irq; + raw_spin_lock_irqsave(&mips_irq_lock, flags); + + irq = mips_pcibios_iack(); + + /* + * The only way we can decide if an interrupt is spurious + * is by checking the 8259 registers. This needs a spinlock + * on an SMP system, so leave it up to the generic code... + */ + + raw_spin_unlock_irqrestore(&mips_irq_lock, flags); + + return irq; +} + +static void malta_hw0_irqdispatch(void) +{ + int irq; + + irq = get_int(); + if (irq < 0) { + /* interrupt has already been cleared */ + return; + } + + do_IRQ(MALTA_INT_BASE + irq); + +#ifdef CONFIG_MIPS_VPE_APSP_API_MT + if (aprp_hook) + aprp_hook(); +#endif +} + +static irqreturn_t i8259_handler(int irq, void *dev_id) +{ + malta_hw0_irqdispatch(); + return IRQ_HANDLED; +} + +static void corehi_irqdispatch(void) +{ + unsigned int intedge, intsteer, pcicmd, pcibadaddr; + unsigned int pcimstat, intisr, inten, intpol; + unsigned int intrcause, datalo, datahi; + struct pt_regs *regs = get_irq_regs(); + + pr_emerg("CoreHI interrupt, shouldn't happen, we die here!\n"); + pr_emerg("epc : %08lx\nStatus: %08lx\n" + "Cause : %08lx\nbadVaddr : %08lx\n", + regs->cp0_epc, regs->cp0_status, + regs->cp0_cause, regs->cp0_badvaddr); + + /* Read all the registers and then print them as there is a + problem with interspersed printk's upsetting the Bonito controller. + Do it for the others too. + */ + + switch (mips_revision_sconid) { + case MIPS_REVISION_SCON_SOCIT: + case MIPS_REVISION_SCON_ROCIT: + case MIPS_REVISION_SCON_SOCITSC: + case MIPS_REVISION_SCON_SOCITSCP: + ll_msc_irq(); + break; + case MIPS_REVISION_SCON_GT64120: + intrcause = GT_READ(GT_INTRCAUSE_OFS); + datalo = GT_READ(GT_CPUERR_ADDRLO_OFS); + datahi = GT_READ(GT_CPUERR_ADDRHI_OFS); + pr_emerg("GT_INTRCAUSE = %08x\n", intrcause); + pr_emerg("GT_CPUERR_ADDR = %02x%08x\n", + datahi, datalo); + break; + case MIPS_REVISION_SCON_BONITO: + pcibadaddr = BONITO_PCIBADADDR; + pcimstat = BONITO_PCIMSTAT; + intisr = BONITO_INTISR; + inten = BONITO_INTEN; + intpol = BONITO_INTPOL; + intedge = BONITO_INTEDGE; + intsteer = BONITO_INTSTEER; + pcicmd = BONITO_PCICMD; + pr_emerg("BONITO_INTISR = %08x\n", intisr); + pr_emerg("BONITO_INTEN = %08x\n", inten); + pr_emerg("BONITO_INTPOL = %08x\n", intpol); + pr_emerg("BONITO_INTEDGE = %08x\n", intedge); + pr_emerg("BONITO_INTSTEER = %08x\n", intsteer); + pr_emerg("BONITO_PCICMD = %08x\n", pcicmd); + pr_emerg("BONITO_PCIBADADDR = %08x\n", pcibadaddr); + pr_emerg("BONITO_PCIMSTAT = %08x\n", pcimstat); + break; + } + + die("CoreHi interrupt", regs); +} + +static irqreturn_t corehi_handler(int irq, void *dev_id) +{ + corehi_irqdispatch(); + return IRQ_HANDLED; +} + +#ifdef CONFIG_MIPS_MT_SMP + +#define MIPS_CPU_IPI_RESCHED_IRQ 0 /* SW int 0 for resched */ +#define C_RESCHED C_SW0 +#define MIPS_CPU_IPI_CALL_IRQ 1 /* SW int 1 for resched */ +#define C_CALL C_SW1 +static int cpu_ipi_resched_irq, cpu_ipi_call_irq; + +static void ipi_resched_dispatch(void) +{ + do_IRQ(MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_RESCHED_IRQ); +} + +static void ipi_call_dispatch(void) +{ + do_IRQ(MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_CALL_IRQ); +} + +static irqreturn_t ipi_resched_interrupt(int irq, void *dev_id) +{ +#ifdef CONFIG_MIPS_VPE_APSP_API_CMP + if (aprp_hook) + aprp_hook(); +#endif + + scheduler_ipi(); + + return IRQ_HANDLED; +} + +static irqreturn_t ipi_call_interrupt(int irq, void *dev_id) +{ + smp_call_function_interrupt(); + + return IRQ_HANDLED; +} + +static struct irqaction irq_resched = { + .handler = ipi_resched_interrupt, + .flags = IRQF_PERCPU, + .name = "IPI_resched" +}; + +static struct irqaction irq_call = { + .handler = ipi_call_interrupt, + .flags = IRQF_PERCPU, + .name = "IPI_call" +}; +#endif /* CONFIG_MIPS_MT_SMP */ + +static struct irqaction i8259irq = { + .handler = i8259_handler, + .name = "XT-PIC cascade", + .flags = IRQF_NO_THREAD, +}; + +static struct irqaction corehi_irqaction = { + .handler = corehi_handler, + .name = "CoreHi", + .flags = IRQF_NO_THREAD, +}; + +static msc_irqmap_t msc_irqmap[] __initdata = { + {MSC01C_INT_TMR, MSC01_IRQ_EDGE, 0}, + {MSC01C_INT_PCI, MSC01_IRQ_LEVEL, 0}, +}; +static int msc_nr_irqs __initdata = ARRAY_SIZE(msc_irqmap); + +static msc_irqmap_t msc_eicirqmap[] __initdata = { + {MSC01E_INT_SW0, MSC01_IRQ_LEVEL, 0}, + {MSC01E_INT_SW1, MSC01_IRQ_LEVEL, 0}, + {MSC01E_INT_I8259A, MSC01_IRQ_LEVEL, 0}, + {MSC01E_INT_SMI, MSC01_IRQ_LEVEL, 0}, + {MSC01E_INT_COREHI, MSC01_IRQ_LEVEL, 0}, + {MSC01E_INT_CORELO, MSC01_IRQ_LEVEL, 0}, + {MSC01E_INT_TMR, MSC01_IRQ_EDGE, 0}, + {MSC01E_INT_PCI, MSC01_IRQ_LEVEL, 0}, + {MSC01E_INT_PERFCTR, MSC01_IRQ_LEVEL, 0}, + {MSC01E_INT_CPUCTR, MSC01_IRQ_LEVEL, 0} +}; + +static int msc_nr_eicirqs __initdata = ARRAY_SIZE(msc_eicirqmap); + +void __init arch_init_ipiirq(int irq, struct irqaction *action) +{ + setup_irq(irq, action); + irq_set_handler(irq, handle_percpu_irq); +} + +void __init arch_init_irq(void) +{ + int corehi_irq, i8259_irq; + + init_i8259_irqs(); + + if (!cpu_has_veic) + mips_cpu_irq_init(); + + if (mips_cm_present()) { + write_gcr_gic_base(GIC_BASE_ADDR | CM_GCR_GIC_BASE_GICEN_MSK); + gic_present = 1; + } else { + if (mips_revision_sconid == MIPS_REVISION_SCON_ROCIT) { + _msc01_biu_base = ioremap_nocache(MSC01_BIU_REG_BASE, + MSC01_BIU_ADDRSPACE_SZ); + gic_present = + (__raw_readl(_msc01_biu_base + MSC01_SC_CFG_OFS) & + MSC01_SC_CFG_GICPRES_MSK) >> + MSC01_SC_CFG_GICPRES_SHF; + } + } + if (gic_present) + pr_debug("GIC present\n"); + + switch (mips_revision_sconid) { + case MIPS_REVISION_SCON_SOCIT: + case MIPS_REVISION_SCON_ROCIT: + if (cpu_has_veic) + init_msc_irqs(MIPS_MSC01_IC_REG_BASE, + MSC01E_INT_BASE, msc_eicirqmap, + msc_nr_eicirqs); + else + init_msc_irqs(MIPS_MSC01_IC_REG_BASE, + MSC01C_INT_BASE, msc_irqmap, + msc_nr_irqs); + break; + + case MIPS_REVISION_SCON_SOCITSC: + case MIPS_REVISION_SCON_SOCITSCP: + if (cpu_has_veic) + init_msc_irqs(MIPS_SOCITSC_IC_REG_BASE, + MSC01E_INT_BASE, msc_eicirqmap, + msc_nr_eicirqs); + else + init_msc_irqs(MIPS_SOCITSC_IC_REG_BASE, + MSC01C_INT_BASE, msc_irqmap, + msc_nr_irqs); + } + + if (gic_present) { + int i; + + gic_init(GIC_BASE_ADDR, GIC_ADDRSPACE_SZ, MIPSCPU_INT_GIC, + MIPS_GIC_IRQ_BASE); + if (!mips_cm_present()) { + /* Enable the GIC */ + i = __raw_readl(_msc01_biu_base + MSC01_SC_CFG_OFS); + __raw_writel(i | (0x1 << MSC01_SC_CFG_GICENA_SHF), + _msc01_biu_base + MSC01_SC_CFG_OFS); + pr_debug("GIC Enabled\n"); + } + i8259_irq = MIPS_GIC_IRQ_BASE + GIC_INT_I8259A; + corehi_irq = MIPS_CPU_IRQ_BASE + MIPSCPU_INT_COREHI; + } else { +#if defined(CONFIG_MIPS_MT_SMP) + /* set up ipi interrupts */ + if (cpu_has_veic) { + set_vi_handler (MSC01E_INT_SW0, ipi_resched_dispatch); + set_vi_handler (MSC01E_INT_SW1, ipi_call_dispatch); + cpu_ipi_resched_irq = MSC01E_INT_SW0; + cpu_ipi_call_irq = MSC01E_INT_SW1; + } else { + cpu_ipi_resched_irq = MIPS_CPU_IRQ_BASE + + MIPS_CPU_IPI_RESCHED_IRQ; + cpu_ipi_call_irq = MIPS_CPU_IRQ_BASE + + MIPS_CPU_IPI_CALL_IRQ; + } + arch_init_ipiirq(cpu_ipi_resched_irq, &irq_resched); + arch_init_ipiirq(cpu_ipi_call_irq, &irq_call); +#endif + if (cpu_has_veic) { + set_vi_handler(MSC01E_INT_I8259A, + malta_hw0_irqdispatch); + set_vi_handler(MSC01E_INT_COREHI, + corehi_irqdispatch); + i8259_irq = MSC01E_INT_BASE + MSC01E_INT_I8259A; + corehi_irq = MSC01E_INT_BASE + MSC01E_INT_COREHI; + } else { + i8259_irq = MIPS_CPU_IRQ_BASE + MIPSCPU_INT_I8259A; + corehi_irq = MIPS_CPU_IRQ_BASE + MIPSCPU_INT_COREHI; + } + } + + setup_irq(i8259_irq, &i8259irq); + setup_irq(corehi_irq, &corehi_irqaction); +} + +void malta_be_init(void) +{ + /* Could change CM error mask register. */ +} + + +static char *tr[8] = { + "mem", "gcr", "gic", "mmio", + "0x04", "0x05", "0x06", "0x07" +}; + +static char *mcmd[32] = { + [0x00] = "0x00", + [0x01] = "Legacy Write", + [0x02] = "Legacy Read", + [0x03] = "0x03", + [0x04] = "0x04", + [0x05] = "0x05", + [0x06] = "0x06", + [0x07] = "0x07", + [0x08] = "Coherent Read Own", + [0x09] = "Coherent Read Share", + [0x0a] = "Coherent Read Discard", + [0x0b] = "Coherent Ready Share Always", + [0x0c] = "Coherent Upgrade", + [0x0d] = "Coherent Writeback", + [0x0e] = "0x0e", + [0x0f] = "0x0f", + [0x10] = "Coherent Copyback", + [0x11] = "Coherent Copyback Invalidate", + [0x12] = "Coherent Invalidate", + [0x13] = "Coherent Write Invalidate", + [0x14] = "Coherent Completion Sync", + [0x15] = "0x15", + [0x16] = "0x16", + [0x17] = "0x17", + [0x18] = "0x18", + [0x19] = "0x19", + [0x1a] = "0x1a", + [0x1b] = "0x1b", + [0x1c] = "0x1c", + [0x1d] = "0x1d", + [0x1e] = "0x1e", + [0x1f] = "0x1f" +}; + +static char *core[8] = { + "Invalid/OK", "Invalid/Data", + "Shared/OK", "Shared/Data", + "Modified/OK", "Modified/Data", + "Exclusive/OK", "Exclusive/Data" +}; + +static char *causes[32] = { + "None", "GC_WR_ERR", "GC_RD_ERR", "COH_WR_ERR", + "COH_RD_ERR", "MMIO_WR_ERR", "MMIO_RD_ERR", "0x07", + "0x08", "0x09", "0x0a", "0x0b", + "0x0c", "0x0d", "0x0e", "0x0f", + "0x10", "0x11", "0x12", "0x13", + "0x14", "0x15", "0x16", "INTVN_WR_ERR", + "INTVN_RD_ERR", "0x19", "0x1a", "0x1b", + "0x1c", "0x1d", "0x1e", "0x1f" +}; + +int malta_be_handler(struct pt_regs *regs, int is_fixup) +{ + /* This duplicates the handling in do_be which seems wrong */ + int retval = is_fixup ? MIPS_BE_FIXUP : MIPS_BE_FATAL; + + if (mips_cm_present()) { + unsigned long cm_error = read_gcr_error_cause(); + unsigned long cm_addr = read_gcr_error_addr(); + unsigned long cm_other = read_gcr_error_mult(); + unsigned long cause, ocause; + char buf[256]; + + cause = cm_error & CM_GCR_ERROR_CAUSE_ERRTYPE_MSK; + if (cause != 0) { + cause >>= CM_GCR_ERROR_CAUSE_ERRTYPE_SHF; + if (cause < 16) { + unsigned long cca_bits = (cm_error >> 15) & 7; + unsigned long tr_bits = (cm_error >> 12) & 7; + unsigned long cmd_bits = (cm_error >> 7) & 0x1f; + unsigned long stag_bits = (cm_error >> 3) & 15; + unsigned long sport_bits = (cm_error >> 0) & 7; + + snprintf(buf, sizeof(buf), + "CCA=%lu TR=%s MCmd=%s STag=%lu " + "SPort=%lu\n", + cca_bits, tr[tr_bits], mcmd[cmd_bits], + stag_bits, sport_bits); + } else { + /* glob state & sresp together */ + unsigned long c3_bits = (cm_error >> 18) & 7; + unsigned long c2_bits = (cm_error >> 15) & 7; + unsigned long c1_bits = (cm_error >> 12) & 7; + unsigned long c0_bits = (cm_error >> 9) & 7; + unsigned long sc_bit = (cm_error >> 8) & 1; + unsigned long cmd_bits = (cm_error >> 3) & 0x1f; + unsigned long sport_bits = (cm_error >> 0) & 7; + snprintf(buf, sizeof(buf), + "C3=%s C2=%s C1=%s C0=%s SC=%s " + "MCmd=%s SPort=%lu\n", + core[c3_bits], core[c2_bits], + core[c1_bits], core[c0_bits], + sc_bit ? "True" : "False", + mcmd[cmd_bits], sport_bits); + } + + ocause = (cm_other & CM_GCR_ERROR_MULT_ERR2ND_MSK) >> + CM_GCR_ERROR_MULT_ERR2ND_SHF; + + pr_err("CM_ERROR=%08lx %s <%s>\n", cm_error, + causes[cause], buf); + pr_err("CM_ADDR =%08lx\n", cm_addr); + pr_err("CM_OTHER=%08lx %s\n", cm_other, causes[ocause]); + + /* reprime cause register */ + write_gcr_error_cause(0); + } + } + + return retval; +} diff --git a/arch/mips/mti-malta/malta-memory.c b/arch/mips/mti-malta/malta-memory.c new file mode 100644 index 000000000..b769657be --- /dev/null +++ b/arch/mips/mti-malta/malta-memory.c @@ -0,0 +1,211 @@ +/* + * 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. + * + * PROM library functions for acquiring/using memory descriptors given to + * us from the YAMON. + * + * Copyright (C) 1999,2000,2012 MIPS Technologies, Inc. + * All rights reserved. + * Authors: Carsten Langgaard <carstenl@mips.com> + * Steven J. Hill <sjhill@mips.com> + */ +#include <linux/init.h> +#include <linux/bootmem.h> +#include <linux/string.h> + +#include <asm/bootinfo.h> +#include <asm/cdmm.h> +#include <asm/maar.h> +#include <asm/sections.h> +#include <asm/fw/fw.h> + +static fw_memblock_t mdesc[FW_MAX_MEMBLOCKS]; + +/* determined physical memory size, not overridden by command line args */ +unsigned long physical_memsize = 0L; + +fw_memblock_t * __init fw_getmdesc(int eva) +{ + char *memsize_str, *ememsize_str = NULL, *ptr; + unsigned long memsize = 0, ememsize = 0; + static char cmdline[COMMAND_LINE_SIZE] __initdata; + int tmp; + + /* otherwise look in the environment */ + + memsize_str = fw_getenv("memsize"); + if (memsize_str) { + tmp = kstrtoul(memsize_str, 0, &memsize); + if (tmp) + pr_warn("Failed to read the 'memsize' env variable.\n"); + } + if (eva) { + /* Look for ememsize for EVA */ + ememsize_str = fw_getenv("ememsize"); + if (ememsize_str) { + tmp = kstrtoul(ememsize_str, 0, &ememsize); + if (tmp) + pr_warn("Failed to read the 'ememsize' env variable.\n"); + } + } + if (!memsize && !ememsize) { + pr_warn("memsize not set in YAMON, set to default (32Mb)\n"); + physical_memsize = 0x02000000; + } else { + if (memsize > (256 << 20)) { /* memsize should be capped to 256M */ + pr_warn("Unsupported memsize value (0x%lx) detected! " + "Using 0x10000000 (256M) instead\n", + memsize); + memsize = 256 << 20; + } + /* If ememsize is set, then set physical_memsize to that */ + physical_memsize = ememsize ? : memsize; + } + +#ifdef CONFIG_CPU_BIG_ENDIAN + /* SOC-it swaps, or perhaps doesn't swap, when DMA'ing the last + word of physical memory */ + physical_memsize -= PAGE_SIZE; +#endif + + /* Check the command line for a memsize directive that overrides + the physical/default amount */ + strcpy(cmdline, arcs_cmdline); + ptr = strstr(cmdline, "memsize="); + if (ptr && (ptr != cmdline) && (*(ptr - 1) != ' ')) + ptr = strstr(ptr, " memsize="); + /* And now look for ememsize */ + if (eva) { + ptr = strstr(cmdline, "ememsize="); + if (ptr && (ptr != cmdline) && (*(ptr - 1) != ' ')) + ptr = strstr(ptr, " ememsize="); + } + + if (ptr) + memsize = memparse(ptr + 8 + (eva ? 1 : 0), &ptr); + else + memsize = physical_memsize; + + /* Last 64K for HIGHMEM arithmetics */ + if (memsize > 0x7fff0000) + memsize = 0x7fff0000; + + memset(mdesc, 0, sizeof(mdesc)); + + mdesc[0].type = fw_dontuse; + mdesc[0].base = PHYS_OFFSET; + mdesc[0].size = 0x00001000; + + mdesc[1].type = fw_code; + mdesc[1].base = mdesc[0].base + 0x00001000UL; + mdesc[1].size = 0x000ef000; + + /* + * 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 = fw_dontuse; + mdesc[2].base = mdesc[0].base + 0x000f0000UL; + mdesc[2].size = 0x00010000; + + mdesc[3].type = fw_dontuse; + mdesc[3].base = mdesc[0].base + 0x00100000UL; + mdesc[3].size = CPHYSADDR(PFN_ALIGN((unsigned long)&_end)) - + 0x00100000UL; + + mdesc[4].type = fw_free; + mdesc[4].base = mdesc[0].base + CPHYSADDR(PFN_ALIGN(&_end)); + mdesc[4].size = memsize - CPHYSADDR(mdesc[4].base); + + return &mdesc[0]; +} + +static void free_init_pages_eva_malta(void *begin, void *end) +{ + free_init_pages("unused kernel", __pa_symbol((unsigned long *)begin), + __pa_symbol((unsigned long *)end)); +} + +static int __init fw_memtype_classify(unsigned int type) +{ + switch (type) { + case fw_free: + return BOOT_MEM_RAM; + case fw_code: + return BOOT_MEM_ROM_DATA; + default: + return BOOT_MEM_RESERVED; + } +} + +void __init fw_meminit(void) +{ + fw_memblock_t *p; + + p = fw_getmdesc(config_enabled(CONFIG_EVA)); + free_init_pages_eva = (config_enabled(CONFIG_EVA) ? + free_init_pages_eva_malta : NULL); + + while (p->size) { + long type; + unsigned long base, size; + + type = fw_memtype_classify(p->type); + base = p->base; + size = p->size; + + add_memory_region(base, size, type); + p++; + } +} + +void __init prom_free_prom_memory(void) +{ + 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; + free_init_pages("YAMON memory", + addr, addr + boot_mem_map.map[i].size); + } +} + +unsigned platform_maar_init(unsigned num_pairs) +{ + phys_addr_t mem_end = (physical_memsize & ~0xffffull) - 1; + struct maar_config cfg[] = { + /* DRAM preceding I/O */ + { 0x00000000, 0x0fffffff, MIPS_MAAR_S }, + + /* DRAM following I/O */ + { 0x20000000, mem_end, MIPS_MAAR_S }, + + /* DRAM alias in upper half of physical */ + { 0x80000000, 0x80000000 + mem_end, MIPS_MAAR_S }, + }; + unsigned i, num_cfg = ARRAY_SIZE(cfg); + + /* If DRAM fits before I/O, drop the region following it */ + if (physical_memsize <= 0x10000000) { + num_cfg--; + for (i = 1; i < num_cfg; i++) + cfg[i] = cfg[i + 1]; + } + + return maar_config(cfg, num_cfg, num_pairs); +} + +phys_addr_t mips_cdmm_phys_base(void) +{ + /* This address is "typically unused" */ + return 0x1fc10000; +} diff --git a/arch/mips/mti-malta/malta-platform.c b/arch/mips/mti-malta/malta-platform.c new file mode 100644 index 000000000..e1dd1c1d3 --- /dev/null +++ b/arch/mips/mti-malta/malta-platform.c @@ -0,0 +1,147 @@ +/* + * 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) 2006, 07 MIPS Technologies, Inc. + * written by Ralf Baechle (ralf@linux-mips.org) + * written by Ralf Baechle <ralf@linux-mips.org> + * + * Copyright (C) 2008 Wind River Systems, Inc. + * updated by Tiejun Chen <tiejun.chen@windriver.com> + * + * 1. Probe driver for the Malta's UART ports: + * + * o 2 ports in the SMC SuperIO + * o 1 port in the CBUS UART, a discrete 16550 which normally is only used + * for bringups. + * + * We don't use 8250_platform.c on Malta as it would result in the CBUS + * UART becoming ttyS0. + * + * 2. Register RTC-CMOS platform device on Malta. + */ +#include <linux/init.h> +#include <linux/serial_8250.h> +#include <linux/mc146818rtc.h> +#include <linux/module.h> +#include <linux/irq.h> +#include <linux/mtd/partitions.h> +#include <linux/mtd/physmap.h> +#include <linux/platform_device.h> +#include <asm/mips-boards/maltaint.h> +#include <mtd/mtd-abi.h> + +#define SMC_PORT(base, int) \ +{ \ + .iobase = base, \ + .irq = int, \ + .uartclk = 1843200, \ + .iotype = UPIO_PORT, \ + .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST, \ + .regshift = 0, \ +} + +#define CBUS_UART_FLAGS (UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_IOREMAP) + +static struct plat_serial8250_port uart8250_data[] = { + SMC_PORT(0x3F8, 4), + SMC_PORT(0x2F8, 3), +#ifndef CONFIG_MIPS_CMP + { + .mapbase = 0x1f000900, /* The CBUS UART */ + .irq = MIPS_CPU_IRQ_BASE + MIPSCPU_INT_MB2, + .uartclk = 3686400, /* Twice the usual clk! */ + .iotype = UPIO_MEM32, + .flags = CBUS_UART_FLAGS, + .regshift = 3, + }, +#endif + { }, +}; + +static struct platform_device malta_uart8250_device = { + .name = "serial8250", + .id = PLAT8250_DEV_PLATFORM, + .dev = { + .platform_data = uart8250_data, + }, +}; + +struct resource malta_rtc_resources[] = { + { + .start = RTC_PORT(0), + .end = RTC_PORT(7), + .flags = IORESOURCE_IO, + }, { + .start = RTC_IRQ, + .end = RTC_IRQ, + .flags = IORESOURCE_IRQ, + } +}; + +static struct platform_device malta_rtc_device = { + .name = "rtc_cmos", + .id = -1, + .resource = malta_rtc_resources, + .num_resources = ARRAY_SIZE(malta_rtc_resources), +}; + +static struct mtd_partition malta_mtd_partitions[] = { + { + .name = "YAMON", + .offset = 0x0, + .size = 0x100000, + .mask_flags = MTD_WRITEABLE + }, { + .name = "User FS", + .offset = 0x100000, + .size = 0x2e0000 + }, { + .name = "Board Config", + .offset = 0x3e0000, + .size = 0x020000, + .mask_flags = MTD_WRITEABLE + } +}; + +static struct physmap_flash_data malta_flash_data = { + .width = 4, + .nr_parts = ARRAY_SIZE(malta_mtd_partitions), + .parts = malta_mtd_partitions +}; + +static struct resource malta_flash_resource = { + .start = 0x1e000000, + .end = 0x1e3fffff, + .flags = IORESOURCE_MEM +}; + +static struct platform_device malta_flash_device = { + .name = "physmap-flash", + .id = 0, + .dev = { + .platform_data = &malta_flash_data, + }, + .num_resources = 1, + .resource = &malta_flash_resource, +}; + +static struct platform_device *malta_devices[] __initdata = { + &malta_uart8250_device, + &malta_rtc_device, + &malta_flash_device, +}; + +static int __init malta_add_devices(void) +{ + int err; + + err = platform_add_devices(malta_devices, ARRAY_SIZE(malta_devices)); + if (err) + return err; + + return 0; +} + +device_initcall(malta_add_devices); diff --git a/arch/mips/mti-malta/malta-pm.c b/arch/mips/mti-malta/malta-pm.c new file mode 100644 index 000000000..c1e456c01 --- /dev/null +++ b/arch/mips/mti-malta/malta-pm.c @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2014 Imagination Technologies + * Author: Paul Burton <paul.burton@imgtec.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/io.h> +#include <linux/pci.h> + +#include <asm/mach-malta/malta-pm.h> + +static struct pci_bus *pm_pci_bus; +static resource_size_t pm_io_offset; + +int mips_pm_suspend(unsigned state) +{ + int spec_devid; + u16 sts; + + if (!pm_pci_bus || !pm_io_offset) + return -ENODEV; + + /* Ensure the power button status is clear */ + while (1) { + sts = inw(pm_io_offset + PIIX4_FUNC3IO_PMSTS); + if (!(sts & PIIX4_FUNC3IO_PMSTS_PWRBTN_STS)) + break; + outw(sts, pm_io_offset + PIIX4_FUNC3IO_PMSTS); + } + + /* Enable entry to suspend */ + outw(state | PIIX4_FUNC3IO_PMCNTRL_SUS_EN, + pm_io_offset + PIIX4_FUNC3IO_PMCNTRL); + + /* If the special cycle occurs too soon this doesn't work... */ + mdelay(10); + + /* + * The PIIX4 will enter the suspend state only after seeing a special + * cycle with the correct magic data on the PCI bus. Generate that + * cycle now. + */ + spec_devid = PCI_DEVID(0, PCI_DEVFN(0x1f, 0x7)); + pci_bus_write_config_dword(pm_pci_bus, spec_devid, 0, + PIIX4_SUSPEND_MAGIC); + + /* Give the system some time to power down */ + mdelay(1000); + + return 0; +} + +static int __init malta_pm_setup(void) +{ + struct pci_dev *dev; + int res, io_region = PCI_BRIDGE_RESOURCES; + + /* Find a reference to the PCI bus */ + pm_pci_bus = pci_find_next_bus(NULL); + if (!pm_pci_bus) { + pr_warn("malta-pm: failed to find reference to PCI bus\n"); + return -ENODEV; + } + + /* Find the PIIX4 PM device */ + dev = pci_get_subsys(PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_INTEL_82371AB_3, PCI_ANY_ID, + PCI_ANY_ID, NULL); + if (!dev) { + pr_warn("malta-pm: failed to find PIIX4 PM\n"); + return -ENODEV; + } + + /* Request access to the PIIX4 PM IO registers */ + res = pci_request_region(dev, io_region, "PIIX4 PM IO registers"); + if (res) { + pr_warn("malta-pm: failed to request PM IO registers (%d)\n", + res); + pci_dev_put(dev); + return -ENODEV; + } + + /* Find the offset to the PIIX4 PM IO registers */ + pm_io_offset = pci_resource_start(dev, io_region); + + pci_dev_put(dev); + return 0; +} + +late_initcall(malta_pm_setup); diff --git a/arch/mips/mti-malta/malta-reset.c b/arch/mips/mti-malta/malta-reset.c new file mode 100644 index 000000000..2fd2cc2c5 --- /dev/null +++ b/arch/mips/mti-malta/malta-reset.c @@ -0,0 +1,47 @@ +/* + * 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. + * + * Carsten Langgaard, carstenl@mips.com + * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved. + */ +#include <linux/io.h> +#include <linux/pm.h> + +#include <asm/reboot.h> +#include <asm/mach-malta/malta-pm.h> + +#define SOFTRES_REG 0x1f000500 +#define GORESET 0x42 + +static void mips_machine_restart(char *command) +{ + unsigned int __iomem *softres_reg = + ioremap(SOFTRES_REG, sizeof(unsigned int)); + + __raw_writel(GORESET, softres_reg); +} + +static void mips_machine_halt(void) +{ + while (true); +} + +static void mips_machine_power_off(void) +{ + mips_pm_suspend(PIIX4_FUNC3IO_PMCNTRL_SUS_TYP_SOFF); + + pr_info("Failed to power down, resetting\n"); + mips_machine_restart(NULL); +} + +static int __init mips_reboot_setup(void) +{ + _machine_restart = mips_machine_restart; + _machine_halt = mips_machine_halt; + pm_power_off = mips_machine_power_off; + + return 0; +} +arch_initcall(mips_reboot_setup); diff --git a/arch/mips/mti-malta/malta-setup.c b/arch/mips/mti-malta/malta-setup.c new file mode 100644 index 000000000..db7c9e582 --- /dev/null +++ b/arch/mips/mti-malta/malta-setup.c @@ -0,0 +1,289 @@ +/* + * Carsten Langgaard, carstenl@mips.com + * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. + * Copyright (C) 2008 Dmitri Vorobiev + * + * 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. + */ +#include <linux/cpu.h> +#include <linux/init.h> +#include <linux/sched.h> +#include <linux/ioport.h> +#include <linux/irq.h> +#include <linux/pci.h> +#include <linux/screen_info.h> +#include <linux/time.h> + +#include <asm/fw/fw.h> +#include <asm/mips-cm.h> +#include <asm/mips-boards/generic.h> +#include <asm/mips-boards/malta.h> +#include <asm/mips-boards/maltaint.h> +#include <asm/dma.h> +#include <asm/traps.h> +#ifdef CONFIG_VT +#include <linux/console.h> +#endif + +extern void malta_be_init(void); +extern int malta_be_handler(struct pt_regs *regs, int is_fixup); + +static struct resource standard_io_resources[] = { + { + .name = "dma1", + .start = 0x00, + .end = 0x1f, + .flags = IORESOURCE_BUSY + }, + { + .name = "timer", + .start = 0x40, + .end = 0x5f, + .flags = IORESOURCE_BUSY + }, + { + .name = "keyboard", + .start = 0x60, + .end = 0x6f, + .flags = IORESOURCE_BUSY + }, + { + .name = "dma page reg", + .start = 0x80, + .end = 0x8f, + .flags = IORESOURCE_BUSY + }, + { + .name = "dma2", + .start = 0xc0, + .end = 0xdf, + .flags = IORESOURCE_BUSY + }, +}; + +const char *get_system_type(void) +{ + return "MIPS Malta"; +} + +const char display_string[] = " LINUX ON MALTA "; + +#ifdef CONFIG_BLK_DEV_FD +static void __init fd_activate(void) +{ + /* + * Activate Floppy Controller in the SMSC FDC37M817 Super I/O + * Controller. + * Done by YAMON 2.00 onwards + */ + /* Entering config state. */ + SMSC_WRITE(SMSC_CONFIG_ENTER, SMSC_CONFIG_REG); + + /* Activate floppy controller. */ + SMSC_WRITE(SMSC_CONFIG_DEVNUM, SMSC_CONFIG_REG); + SMSC_WRITE(SMSC_CONFIG_DEVNUM_FLOPPY, SMSC_DATA_REG); + SMSC_WRITE(SMSC_CONFIG_ACTIVATE, SMSC_CONFIG_REG); + SMSC_WRITE(SMSC_CONFIG_ACTIVATE_ENABLE, SMSC_DATA_REG); + + /* Exit config state. */ + SMSC_WRITE(SMSC_CONFIG_EXIT, SMSC_CONFIG_REG); +} +#endif + +static int __init plat_enable_iocoherency(void) +{ + int supported = 0; + if (mips_revision_sconid == MIPS_REVISION_SCON_BONITO) { + if (BONITO_PCICACHECTRL & BONITO_PCICACHECTRL_CPUCOH_PRES) { + BONITO_PCICACHECTRL |= BONITO_PCICACHECTRL_CPUCOH_EN; + pr_info("Enabled Bonito CPU coherency\n"); + supported = 1; + } + if (strstr(fw_getcmdline(), "iobcuncached")) { + BONITO_PCICACHECTRL &= ~BONITO_PCICACHECTRL_IOBCCOH_EN; + BONITO_PCIMEMBASECFG = BONITO_PCIMEMBASECFG & + ~(BONITO_PCIMEMBASECFG_MEMBASE0_CACHED | + BONITO_PCIMEMBASECFG_MEMBASE1_CACHED); + pr_info("Disabled Bonito IOBC coherency\n"); + } else { + BONITO_PCICACHECTRL |= BONITO_PCICACHECTRL_IOBCCOH_EN; + BONITO_PCIMEMBASECFG |= + (BONITO_PCIMEMBASECFG_MEMBASE0_CACHED | + BONITO_PCIMEMBASECFG_MEMBASE1_CACHED); + pr_info("Enabled Bonito IOBC coherency\n"); + } + } else if (mips_cm_numiocu() != 0) { + /* Nothing special needs to be done to enable coherency */ + pr_info("CMP IOCU detected\n"); + if ((*(unsigned int *)0xbf403000 & 0x81) != 0x81) { + pr_crit("IOCU OPERATION DISABLED BY SWITCH - DEFAULTING TO SW IO COHERENCY\n"); + return 0; + } + supported = 1; + } + hw_coherentio = supported; + return supported; +} + +static void __init plat_setup_iocoherency(void) +{ +#ifdef CONFIG_DMA_NONCOHERENT + /* + * Kernel has been configured with software coherency + * but we might choose to turn it off and use hardware + * coherency instead. + */ + if (plat_enable_iocoherency()) { + if (coherentio == 0) + pr_info("Hardware DMA cache coherency disabled\n"); + else + pr_info("Hardware DMA cache coherency enabled\n"); + } else { + if (coherentio == 1) + pr_info("Hardware DMA cache coherency unsupported, but enabled from command line!\n"); + else + pr_info("Software DMA cache coherency enabled\n"); + } +#else + if (!plat_enable_iocoherency()) + panic("Hardware DMA cache coherency not supported!"); +#endif +} + +static void __init pci_clock_check(void) +{ + unsigned int __iomem *jmpr_p = + (unsigned int *) ioremap(MALTA_JMPRS_REG, sizeof(unsigned int)); + int jmpr = (__raw_readl(jmpr_p) >> 2) & 0x07; + static const int pciclocks[] __initconst = { + 33, 20, 25, 30, 12, 16, 37, 10 + }; + int pciclock = pciclocks[jmpr]; + char *optptr, *argptr = fw_getcmdline(); + + /* + * If user passed a pci_clock= option, don't tack on another one + */ + optptr = strstr(argptr, "pci_clock="); + if (optptr && (optptr == argptr || optptr[-1] == ' ')) + return; + + if (pciclock != 33) { + pr_warn("WARNING: PCI clock is %dMHz, setting pci_clock\n", + pciclock); + argptr += strlen(argptr); + sprintf(argptr, " pci_clock=%d", pciclock); + if (pciclock < 20 || pciclock > 66) + pr_warn("WARNING: IDE timing calculations will be " + "incorrect\n"); + } +} + +#if defined(CONFIG_VT) && defined(CONFIG_VGA_CONSOLE) +static void __init screen_info_setup(void) +{ + screen_info = (struct screen_info) { + .orig_x = 0, + .orig_y = 25, + .ext_mem_k = 0, + .orig_video_page = 0, + .orig_video_mode = 0, + .orig_video_cols = 80, + .unused2 = 0, + .orig_video_ega_bx = 0, + .unused3 = 0, + .orig_video_lines = 25, + .orig_video_isVGA = VIDEO_TYPE_VGAC, + .orig_video_points = 16 + }; +} +#endif + +static void __init bonito_quirks_setup(void) +{ + char *argptr; + + argptr = fw_getcmdline(); + if (strstr(argptr, "debug")) { + BONITO_BONGENCFG |= BONITO_BONGENCFG_DEBUGMODE; + pr_info("Enabled Bonito debug mode\n"); + } else + BONITO_BONGENCFG &= ~BONITO_BONGENCFG_DEBUGMODE; + +#ifdef CONFIG_DMA_COHERENT + if (BONITO_PCICACHECTRL & BONITO_PCICACHECTRL_CPUCOH_PRES) { + BONITO_PCICACHECTRL |= BONITO_PCICACHECTRL_CPUCOH_EN; + pr_info("Enabled Bonito CPU coherency\n"); + + argptr = fw_getcmdline(); + if (strstr(argptr, "iobcuncached")) { + BONITO_PCICACHECTRL &= ~BONITO_PCICACHECTRL_IOBCCOH_EN; + BONITO_PCIMEMBASECFG = BONITO_PCIMEMBASECFG & + ~(BONITO_PCIMEMBASECFG_MEMBASE0_CACHED | + BONITO_PCIMEMBASECFG_MEMBASE1_CACHED); + pr_info("Disabled Bonito IOBC coherency\n"); + } else { + BONITO_PCICACHECTRL |= BONITO_PCICACHECTRL_IOBCCOH_EN; + BONITO_PCIMEMBASECFG |= + (BONITO_PCIMEMBASECFG_MEMBASE0_CACHED | + BONITO_PCIMEMBASECFG_MEMBASE1_CACHED); + pr_info("Enabled Bonito IOBC coherency\n"); + } + } else + panic("Hardware DMA cache coherency not supported"); +#endif +} + +void __init plat_mem_setup(void) +{ + unsigned int i; + + if (config_enabled(CONFIG_EVA)) + /* EVA has already been configured in mach-malta/kernel-init.h */ + pr_info("Enhanced Virtual Addressing (EVA) activated\n"); + + mips_pcibios_init(); + + /* Request I/O space for devices used on the Malta board. */ + for (i = 0; i < ARRAY_SIZE(standard_io_resources); i++) + request_resource(&ioport_resource, standard_io_resources+i); + + /* + * Enable DMA channel 4 (cascade channel) in the PIIX4 south bridge. + */ + enable_dma(4); + +#ifdef CONFIG_DMA_COHERENT + if (mips_revision_sconid != MIPS_REVISION_SCON_BONITO) + panic("Hardware DMA cache coherency not supported"); +#endif + + if (mips_revision_sconid == MIPS_REVISION_SCON_BONITO) + bonito_quirks_setup(); + + plat_setup_iocoherency(); + + pci_clock_check(); + +#ifdef CONFIG_BLK_DEV_FD + fd_activate(); +#endif + +#if defined(CONFIG_VT) && defined(CONFIG_VGA_CONSOLE) + screen_info_setup(); +#endif + + board_be_init = malta_be_init; + board_be_handler = malta_be_handler; +} diff --git a/arch/mips/mti-malta/malta-time.c b/arch/mips/mti-malta/malta-time.c new file mode 100644 index 000000000..185e68261 --- /dev/null +++ b/arch/mips/mti-malta/malta-time.c @@ -0,0 +1,211 @@ +/* + * 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/i8253.h> +#include <linux/init.h> +#include <linux/kernel_stat.h> +#include <linux/sched.h> +#include <linux/spinlock.h> +#include <linux/interrupt.h> +#include <linux/irqchip/mips-gic.h> +#include <linux/timex.h> +#include <linux/mc146818rtc.h> + +#include <asm/cpu.h> +#include <asm/mipsregs.h> +#include <asm/mipsmtregs.h> +#include <asm/hardirq.h> +#include <asm/irq.h> +#include <asm/div64.h> +#include <asm/setup.h> +#include <asm/time.h> +#include <asm/mc146818-time.h> +#include <asm/msc01_ic.h> + +#include <asm/mips-boards/generic.h> +#include <asm/mips-boards/maltaint.h> + +static int mips_cpu_timer_irq; +static int mips_cpu_perf_irq; +extern int cp0_perfcount_irq; + +static unsigned int gic_frequency; + +static void mips_timer_dispatch(void) +{ + do_IRQ(mips_cpu_timer_irq); +} + +static void mips_perf_dispatch(void) +{ + do_IRQ(mips_cpu_perf_irq); +} + +static unsigned int freqround(unsigned int freq, unsigned int amount) +{ + freq += amount; + freq -= freq % (amount*2); + return freq; +} + +/* + * Estimate CPU and GIC frequencies. + */ +static void __init estimate_frequencies(void) +{ + unsigned long flags; + unsigned int count, start; + cycle_t giccount = 0, gicstart = 0; + +#if defined(CONFIG_KVM_GUEST) && CONFIG_KVM_GUEST_TIMER_FREQ + mips_hpt_frequency = CONFIG_KVM_GUEST_TIMER_FREQ * 1000000; + return; +#endif + + 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)); + + /* Initialize counters. */ + start = read_c0_count(); + if (gic_present) { + gic_start_count(); + gicstart = gic_read_count(); + } + + /* 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(); + if (gic_present) + giccount = gic_read_count(); + + local_irq_restore(flags); + + count -= start; + mips_hpt_frequency = count; + + if (gic_present) { + giccount -= gicstart; + gic_frequency = giccount; + } +} + +void read_persistent_clock(struct timespec *ts) +{ + ts->tv_sec = mc146818_get_cmos_time(); + ts->tv_nsec = 0; +} + +int get_c0_fdc_int(void) +{ + int mips_cpu_fdc_irq; + + if (cpu_has_veic) + mips_cpu_fdc_irq = -1; + else if (gic_present) + mips_cpu_fdc_irq = gic_get_c0_fdc_int(); + else if (cp0_fdc_irq >= 0) + mips_cpu_fdc_irq = MIPS_CPU_IRQ_BASE + cp0_fdc_irq; + else + mips_cpu_fdc_irq = -1; + + return mips_cpu_fdc_irq; +} + +int get_c0_perfcount_int(void) +{ + if (cpu_has_veic) { + set_vi_handler(MSC01E_INT_PERFCTR, mips_perf_dispatch); + mips_cpu_perf_irq = MSC01E_INT_BASE + MSC01E_INT_PERFCTR; + } else if (gic_present) { + mips_cpu_perf_irq = gic_get_c0_perfcount_int(); + } else if (cp0_perfcount_irq >= 0) { + mips_cpu_perf_irq = MIPS_CPU_IRQ_BASE + cp0_perfcount_irq; + } else { + mips_cpu_perf_irq = -1; + } + + return mips_cpu_perf_irq; +} + +unsigned int get_c0_compare_int(void) +{ + if (cpu_has_veic) { + set_vi_handler(MSC01E_INT_CPUCTR, mips_timer_dispatch); + mips_cpu_timer_irq = MSC01E_INT_BASE + MSC01E_INT_CPUCTR; + } else if (gic_present) { + mips_cpu_timer_irq = gic_get_c0_compare_int(); + } else { + mips_cpu_timer_irq = MIPS_CPU_IRQ_BASE + cp0_compare_irq; + } + + return mips_cpu_timer_irq; +} + +static void __init init_rtc(void) +{ + /* stop the clock whilst setting it up */ + CMOS_WRITE(RTC_SET | RTC_24H, RTC_CONTROL); + + /* 32KHz time base */ + CMOS_WRITE(RTC_REF_CLCK_32KHZ, RTC_FREQ_SELECT); + + /* start the clock */ + CMOS_WRITE(RTC_24H, RTC_CONTROL); +} + +void __init plat_time_init(void) +{ + unsigned int prid = read_c0_prid() & (PRID_COMP_MASK | PRID_IMP_MASK); + unsigned int freq; + + init_rtc(); + estimate_frequencies(); + + freq = mips_hpt_frequency; + if ((prid != (PRID_COMP_MIPS | PRID_IMP_20KC)) && + (prid != (PRID_COMP_MIPS | PRID_IMP_25KF))) + freq *= 2; + freq = freqround(freq, 5000); + printk("CPU frequency %d.%02d MHz\n", freq/1000000, + (freq%1000000)*100/1000000); + + mips_scroll_message(); + +#ifdef CONFIG_I8253 + /* Only Malta has a PIT. */ + setup_pit_timer(); +#endif + +#ifdef CONFIG_MIPS_GIC + if (gic_present) { + freq = freqround(gic_frequency, 5000); + printk("GIC frequency %d.%02d MHz\n", freq/1000000, + (freq%1000000)*100/1000000); +#ifdef CONFIG_CLKSRC_MIPS_GIC + gic_clocksource_init(gic_frequency); +#endif + } +#endif +} |