mirror of
https://github.com/AetherDroid/android_kernel_samsung_on5xelte.git
synced 2025-09-08 17:18:05 -04:00
Fixed MTP to work with TWRP
This commit is contained in:
commit
f6dfaef42e
50820 changed files with 20846062 additions and 0 deletions
13
arch/mips/mti-malta/Makefile
Normal file
13
arch/mips/mti-malta/Makefile
Normal 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
|
11
arch/mips/mti-malta/Platform
Normal file
11
arch/mips/mti-malta/Platform
Normal 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
|
88
arch/mips/mti-malta/malta-amon.c
Normal file
88
arch/mips/mti-malta/malta-amon.c
Normal 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
|
56
arch/mips/mti-malta/malta-display.c
Normal file
56
arch/mips/mti-malta/malta-display.c
Normal 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);
|
||||
}
|
305
arch/mips/mti-malta/malta-init.c
Normal file
305
arch/mips/mti-malta/malta-init.c
Normal 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;
|
||||
}
|
750
arch/mips/mti-malta/malta-int.c
Normal file
750
arch/mips/mti-malta/malta-int.c
Normal 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);
|
||||
}
|
204
arch/mips/mti-malta/malta-memory.c
Normal file
204
arch/mips/mti-malta/malta-memory.c
Normal 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);
|
||||
}
|
147
arch/mips/mti-malta/malta-platform.c
Normal file
147
arch/mips/mti-malta/malta-platform.c
Normal 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);
|
96
arch/mips/mti-malta/malta-pm.c
Normal file
96
arch/mips/mti-malta/malta-pm.c
Normal 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);
|
47
arch/mips/mti-malta/malta-reset.c
Normal file
47
arch/mips/mti-malta/malta-reset.c
Normal 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);
|
289
arch/mips/mti-malta/malta-setup.c
Normal file
289
arch/mips/mti-malta/malta-setup.c
Normal 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;
|
||||
}
|
206
arch/mips/mti-malta/malta-time.c
Normal file
206
arch/mips/mti-malta/malta-time.c
Normal 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();
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue