Fixed MTP to work with TWRP

This commit is contained in:
awab228 2018-06-19 23:16:04 +02:00
commit f6dfaef42e
50820 changed files with 20846062 additions and 0 deletions

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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);
}

View file

@ -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_8250.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_early_serial8250_console(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_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;
}

View file

@ -0,0 +1,750 @@
/*
* 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/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/gic.h>
#include <asm/setup.h>
#include <asm/rtlx.h>
static unsigned long _msc01_biu_base;
static unsigned int ipi_map[NR_CPUS];
static DEFINE_RAW_SPINLOCK(mips_irq_lock);
#ifdef CONFIG_MIPS_GIC_IPI
DECLARE_BITMAP(ipi_ints, GIC_NUM_INTRS);
#endif
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 void malta_ipi_irqdispatch(void)
{
#ifdef CONFIG_MIPS_GIC_IPI
unsigned long irq;
DECLARE_BITMAP(pending, GIC_NUM_INTRS);
gic_get_int_mask(pending, ipi_ints);
irq = find_first_bit(pending, GIC_NUM_INTRS);
while (irq < GIC_NUM_INTRS) {
do_IRQ(MIPS_GIC_IRQ_BASE + irq);
irq = find_next_bit(pending, GIC_NUM_INTRS, irq + 1);
}
#endif
if (gic_compare_int())
do_IRQ(MIPS_GIC_IRQ_BASE);
}
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 inline int clz(unsigned long x)
{
__asm__(
" .set push \n"
" .set mips32 \n"
" clz %0, %1 \n"
" .set pop \n"
: "=r" (x)
: "r" (x));
return x;
}
/*
* Version of ffs that only looks at bits 12..15.
*/
static inline unsigned int irq_ffs(unsigned int pending)
{
#if defined(CONFIG_CPU_MIPS32) || defined(CONFIG_CPU_MIPS64)
return -clz(pending) + 31 - CAUSEB_IP;
#else
unsigned int a0 = 7;
unsigned int t0;
t0 = pending & 0xf000;
t0 = t0 < 1;
t0 = t0 << 2;
a0 = a0 - t0;
pending = pending << t0;
t0 = pending & 0xc000;
t0 = t0 < 1;
t0 = t0 << 1;
a0 = a0 - t0;
pending = pending << t0;
t0 = pending & 0x8000;
t0 = t0 < 1;
/* t0 = t0 << 2; */
a0 = a0 - t0;
/* pending = pending << t0; */
return a0;
#endif
}
/*
* IRQs on the Malta 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)
*
* 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.
*/
asmlinkage void plat_irq_dispatch(void)
{
unsigned int pending = read_c0_cause() & read_c0_status() & ST0_IM;
int irq;
if (unlikely(!pending)) {
spurious_interrupt();
return;
}
irq = irq_ffs(pending);
if (irq == MIPSCPU_INT_I8259A)
malta_hw0_irqdispatch();
else if (gic_present && ((1 << irq) & ipi_map[smp_processor_id()]))
malta_ipi_irqdispatch();
else
do_IRQ(MIPS_CPU_IRQ_BASE + irq);
}
#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);
}
#endif /* CONFIG_MIPS_MT_SMP */
#ifdef CONFIG_MIPS_GIC_IPI
#define GIC_MIPS_CPU_IPI_RESCHED_IRQ 3
#define GIC_MIPS_CPU_IPI_CALL_IRQ 4
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_GIC_IPI */
static int gic_resched_int_base;
static int gic_call_int_base;
#define GIC_RESCHED_INT(cpu) (gic_resched_int_base+(cpu))
#define GIC_CALL_INT(cpu) (gic_call_int_base+(cpu))
unsigned int plat_ipi_call_int_xlate(unsigned int cpu)
{
return GIC_CALL_INT(cpu);
}
unsigned int plat_ipi_resched_int_xlate(unsigned int cpu)
{
return GIC_RESCHED_INT(cpu);
}
static struct irqaction i8259irq = {
.handler = no_action,
.name = "XT-PIC cascade",
.flags = IRQF_NO_THREAD,
};
static struct irqaction corehi_irqaction = {
.handler = no_action,
.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);
/*
* This GIC specific tabular array defines the association between External
* Interrupts and CPUs/Core Interrupts. The nature of the External
* Interrupts is also defined here - polarity/trigger.
*/
#define GIC_CPU_NMI GIC_MAP_TO_NMI_MSK
#define X GIC_UNUSED
static struct gic_intr_map gic_intr_map[GIC_NUM_INTRS] = {
{ X, X, X, X, 0 },
{ X, X, X, X, 0 },
{ X, X, X, X, 0 },
{ 0, GIC_CPU_INT0, GIC_POL_POS, GIC_TRIG_LEVEL, GIC_FLAG_TRANSPARENT },
{ 0, GIC_CPU_INT1, GIC_POL_POS, GIC_TRIG_LEVEL, GIC_FLAG_TRANSPARENT },
{ 0, GIC_CPU_INT2, GIC_POL_POS, GIC_TRIG_LEVEL, GIC_FLAG_TRANSPARENT },
{ 0, GIC_CPU_INT3, GIC_POL_POS, GIC_TRIG_LEVEL, GIC_FLAG_TRANSPARENT },
{ 0, GIC_CPU_INT4, GIC_POL_POS, GIC_TRIG_LEVEL, GIC_FLAG_TRANSPARENT },
{ 0, GIC_CPU_INT3, GIC_POL_POS, GIC_TRIG_LEVEL, GIC_FLAG_TRANSPARENT },
{ 0, GIC_CPU_INT3, GIC_POL_POS, GIC_TRIG_LEVEL, GIC_FLAG_TRANSPARENT },
{ X, X, X, X, 0 },
{ X, X, X, X, 0 },
{ 0, GIC_CPU_INT3, GIC_POL_POS, GIC_TRIG_LEVEL, GIC_FLAG_TRANSPARENT },
{ 0, GIC_CPU_NMI, GIC_POL_POS, GIC_TRIG_LEVEL, GIC_FLAG_TRANSPARENT },
{ 0, GIC_CPU_NMI, GIC_POL_POS, GIC_TRIG_LEVEL, GIC_FLAG_TRANSPARENT },
{ X, X, X, X, 0 },
/* The remainder of this table is initialised by fill_ipi_map */
};
#undef X
#ifdef CONFIG_MIPS_GIC_IPI
static void __init fill_ipi_map1(int baseintr, int cpu, int cpupin)
{
int intr = baseintr + cpu;
gic_intr_map[intr].cpunum = cpu;
gic_intr_map[intr].pin = cpupin;
gic_intr_map[intr].polarity = GIC_POL_POS;
gic_intr_map[intr].trigtype = GIC_TRIG_EDGE;
gic_intr_map[intr].flags = 0;
ipi_map[cpu] |= (1 << (cpupin + 2));
bitmap_set(ipi_ints, intr, 1);
}
static void __init fill_ipi_map(void)
{
int cpu;
for (cpu = 0; cpu < nr_cpu_ids; cpu++) {
fill_ipi_map1(gic_resched_int_base, cpu, GIC_CPU_INT1);
fill_ipi_map1(gic_call_int_base, cpu, GIC_CPU_INT2);
}
}
#endif
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)
{
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 = (unsigned long)
ioremap_nocache(MSC01_BIU_REG_BASE,
MSC01_BIU_ADDRSPACE_SZ);
gic_present = (REG(_msc01_biu_base, MSC01_SC_CFG) &
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 (cpu_has_veic) {
set_vi_handler(MSC01E_INT_I8259A, malta_hw0_irqdispatch);
set_vi_handler(MSC01E_INT_COREHI, corehi_irqdispatch);
setup_irq(MSC01E_INT_BASE+MSC01E_INT_I8259A, &i8259irq);
setup_irq(MSC01E_INT_BASE+MSC01E_INT_COREHI, &corehi_irqaction);
} else if (cpu_has_vint) {
set_vi_handler(MIPSCPU_INT_I8259A, malta_hw0_irqdispatch);
set_vi_handler(MIPSCPU_INT_COREHI, corehi_irqdispatch);
setup_irq(MIPS_CPU_IRQ_BASE+MIPSCPU_INT_I8259A, &i8259irq);
setup_irq(MIPS_CPU_IRQ_BASE+MIPSCPU_INT_COREHI,
&corehi_irqaction);
} else {
setup_irq(MIPS_CPU_IRQ_BASE+MIPSCPU_INT_I8259A, &i8259irq);
setup_irq(MIPS_CPU_IRQ_BASE+MIPSCPU_INT_COREHI,
&corehi_irqaction);
}
if (gic_present) {
/* FIXME */
int i;
#if defined(CONFIG_MIPS_GIC_IPI)
gic_call_int_base = GIC_NUM_INTRS -
(NR_CPUS - nr_cpu_ids) * 2 - nr_cpu_ids;
gic_resched_int_base = gic_call_int_base - nr_cpu_ids;
fill_ipi_map();
#endif
gic_init(GIC_BASE_ADDR, GIC_ADDRSPACE_SZ, gic_intr_map,
ARRAY_SIZE(gic_intr_map), MIPS_GIC_IRQ_BASE);
if (!mips_cm_present()) {
/* Enable the GIC */
i = REG(_msc01_biu_base, MSC01_SC_CFG);
REG(_msc01_biu_base, MSC01_SC_CFG) =
(i | (0x1 << MSC01_SC_CFG_GICENA_SHF));
pr_debug("GIC Enabled\n");
}
#if defined(CONFIG_MIPS_GIC_IPI)
/* set up ipi interrupts */
if (cpu_has_vint) {
set_vi_handler(MIPSCPU_INT_IPI0, malta_ipi_irqdispatch);
set_vi_handler(MIPSCPU_INT_IPI1, malta_ipi_irqdispatch);
}
/* Argh.. this really needs sorting out.. */
pr_info("CPU%d: status register was %08x\n",
smp_processor_id(), read_c0_status());
write_c0_status(read_c0_status() | STATUSF_IP3 | STATUSF_IP4);
pr_info("CPU%d: status register now %08x\n",
smp_processor_id(), read_c0_status());
write_c0_status(0x1100dc00);
pr_info("CPU%d: status register frc %08x\n",
smp_processor_id(), read_c0_status());
for (i = 0; i < nr_cpu_ids; i++) {
arch_init_ipiirq(MIPS_GIC_IRQ_BASE +
GIC_RESCHED_INT(i), &irq_resched);
arch_init_ipiirq(MIPS_GIC_IRQ_BASE +
GIC_CALL_INT(i), &irq_call);
}
#endif
} 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 {
if (cpu_has_vint) {
set_vi_handler (MIPS_CPU_IPI_RESCHED_IRQ,
ipi_resched_dispatch);
set_vi_handler (MIPS_CPU_IPI_CALL_IRQ,
ipi_call_dispatch);
}
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
}
}
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;
}
void gic_enable_interrupt(int irq_vec)
{
GIC_SET_INTR_MASK(irq_vec);
}
void gic_disable_interrupt(int irq_vec)
{
GIC_CLR_INTR_MASK(irq_vec);
}
void gic_irq_ack(struct irq_data *d)
{
int irq = (d->irq - gic_irq_base);
GIC_CLR_INTR_MASK(irq);
if (gic_irq_flags[irq] & GIC_TRIG_EDGE)
GICWRITE(GIC_REG(SHARED, GIC_SH_WEDGE), irq);
}
void gic_finish_irq(struct irq_data *d)
{
/* Enable interrupts. */
GIC_SET_INTR_MASK(d->irq - gic_irq_base);
}
void __init gic_platform_init(int irqs, struct irq_chip *irq_controller)
{
int i;
for (i = gic_irq_base; i < (gic_irq_base + irqs); i++)
irq_set_chip(i, irq_controller);
}

View file

@ -0,0 +1,204 @@
/*
* 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/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);
}

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -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;
}

View file

@ -0,0 +1,206 @@
/*
* 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/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/gic.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 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;
#ifdef CONFIG_IRQ_GIC
unsigned int giccount = 0, gicstart = 0;
#endif
#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();
#ifdef CONFIG_IRQ_GIC
if (gic_present)
GICREAD(GIC_REG(SHARED, GIC_SH_COUNTER_31_00), gicstart);
#endif
/* 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();
#ifdef CONFIG_IRQ_GIC
if (gic_present)
GICREAD(GIC_REG(SHARED, GIC_SH_COUNTER_31_00), giccount);
#endif
local_irq_restore(flags);
count -= start;
mips_hpt_frequency = count;
#ifdef CONFIG_IRQ_GIC
if (gic_present) {
giccount -= gicstart;
gic_frequency = giccount;
}
#endif
}
void read_persistent_clock(struct timespec *ts)
{
ts->tv_sec = mc146818_get_cmos_time();
ts->tv_nsec = 0;
}
static void __init plat_perf_setup(void)
{
#ifdef MSC01E_INT_BASE
if (cpu_has_veic) {
set_vi_handler(MSC01E_INT_PERFCTR, mips_perf_dispatch);
mips_cpu_perf_irq = MSC01E_INT_BASE + MSC01E_INT_PERFCTR;
} else
#endif
if (cp0_perfcount_irq >= 0) {
if (cpu_has_vint)
set_vi_handler(cp0_perfcount_irq, mips_perf_dispatch);
mips_cpu_perf_irq = MIPS_CPU_IRQ_BASE + cp0_perfcount_irq;
#ifdef CONFIG_SMP
irq_set_handler(mips_cpu_perf_irq, handle_percpu_irq);
#endif
}
}
unsigned int get_c0_compare_int(void)
{
#ifdef MSC01E_INT_BASE
if (cpu_has_veic) {
set_vi_handler(MSC01E_INT_CPUCTR, mips_timer_dispatch);
mips_cpu_timer_irq = MSC01E_INT_BASE + MSC01E_INT_CPUCTR;
} else
#endif
{
if (cpu_has_vint)
set_vi_handler(cp0_compare_irq, mips_timer_dispatch);
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_IRQ_GIC
if (gic_present) {
freq = freqround(gic_frequency, 5000);
printk("GIC frequency %d.%02d MHz\n", freq/1000000,
(freq%1000000)*100/1000000);
#ifdef CONFIG_CSRC_GIC
gic_clocksource_init(gic_frequency);
#endif
}
#endif
plat_perf_setup();
}