Commit f10f114f authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'upstream' of git://ftp.linux-mips.org/pub/scm/upstream-linus

* 'upstream' of git://ftp.linux-mips.org/pub/scm/upstream-linus:
  [MIPS] time: Make c0_compare_int_usable more bullet proof
  [MIPS] Kbuild: Use the new cc-cross-prefix feature.
  [MIPS] Fix include wrapper symbol to something sane.
  [MIPS] Malta: Delete dead code.
  [MIPS] time: Add GT641xx timer0 clockevent driver
  [MIPS] time: SMP-proofing of Sibyte clockevent/clocksource code.
  [MIPS] time: SMP/NUMA-proofing of IP27 HUB RT timer code.
  [MIPS] time: Fix calculation in clockevent_set_clock()
parents 0c326331 dab969c0
...@@ -66,6 +66,7 @@ config BCM47XX ...@@ -66,6 +66,7 @@ config BCM47XX
config MIPS_COBALT config MIPS_COBALT
bool "Cobalt Server" bool "Cobalt Server"
select CEVT_R4K select CEVT_R4K
select CEVT_GT641XX
select DMA_NONCOHERENT select DMA_NONCOHERENT
select HW_HAS_PCI select HW_HAS_PCI
select I8253 select I8253
...@@ -729,6 +730,9 @@ config ARCH_MAY_HAVE_PC_FDC ...@@ -729,6 +730,9 @@ config ARCH_MAY_HAVE_PC_FDC
config BOOT_RAW config BOOT_RAW
bool bool
config CEVT_GT641XX
bool
config CEVT_R4K config CEVT_R4K
bool bool
......
...@@ -6,18 +6,6 @@ config TRACE_IRQFLAGS_SUPPORT ...@@ -6,18 +6,6 @@ config TRACE_IRQFLAGS_SUPPORT
source "lib/Kconfig.debug" source "lib/Kconfig.debug"
config CROSSCOMPILE
bool "Are you using a crosscompiler"
help
Say Y here if you are compiling the kernel on a different
architecture than the one it is intended to run on. This is just a
convenience option which will select the appropriate value for
the CROSS_COMPILE make variable which otherwise has to be passed on
the command line from mips-linux-, mipsel-linux-, mips64-linux- and
mips64el-linux- as appropriate for a particular kernel configuration.
You will have to pass the value for CROSS_COMPILE manually if the
name prefix for your tools is different.
config CMDLINE config CMDLINE
string "Default kernel command string" string "Default kernel command string"
default "" default ""
......
...@@ -18,15 +18,15 @@ cflags-y := ...@@ -18,15 +18,15 @@ cflags-y :=
# Select the object file format to substitute into the linker script. # Select the object file format to substitute into the linker script.
# #
ifdef CONFIG_CPU_LITTLE_ENDIAN ifdef CONFIG_CPU_LITTLE_ENDIAN
32bit-tool-prefix = mipsel-linux- 32bit-tool-archpref = mipsel
64bit-tool-prefix = mips64el-linux- 64bit-tool-archpref = mips64el
32bit-bfd = elf32-tradlittlemips 32bit-bfd = elf32-tradlittlemips
64bit-bfd = elf64-tradlittlemips 64bit-bfd = elf64-tradlittlemips
32bit-emul = elf32ltsmip 32bit-emul = elf32ltsmip
64bit-emul = elf64ltsmip 64bit-emul = elf64ltsmip
else else
32bit-tool-prefix = mips-linux- 32bit-tool-archpref = mips
64bit-tool-prefix = mips64-linux- 64bit-tool-archpref = mips64
32bit-bfd = elf32-tradbigmips 32bit-bfd = elf32-tradbigmips
64bit-bfd = elf64-tradbigmips 64bit-bfd = elf64-tradbigmips
32bit-emul = elf32btsmip 32bit-emul = elf32btsmip
...@@ -34,16 +34,18 @@ else ...@@ -34,16 +34,18 @@ else
endif endif
ifdef CONFIG_32BIT ifdef CONFIG_32BIT
tool-prefix = $(32bit-tool-prefix) tool-archpref = $(32bit-tool-archpref)
UTS_MACHINE := mips UTS_MACHINE := mips
endif endif
ifdef CONFIG_64BIT ifdef CONFIG_64BIT
tool-prefix = $(64bit-tool-prefix) tool-archpref = $(64bit-tool-archpref)
UTS_MACHINE := mips64 UTS_MACHINE := mips64
endif endif
ifdef CONFIG_CROSSCOMPILE ifneq ($(SUBARCH),$(ARCH))
CROSS_COMPILE := $(tool-prefix) ifeq ($(CROSS_COMPILE),)
CROSS_COMPILE := $(call cc-cross-prefix, $(tool-archpref)-linux- $(tool-archpref)-gnu-linux- $(tool-archpref)-unknown-gnu-linux-)
endif
endif endif
ifdef CONFIG_32BIT ifdef CONFIG_32BIT
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
# Makefile for the Cobalt micro systems family specific parts of the kernel # Makefile for the Cobalt micro systems family specific parts of the kernel
# #
obj-y := buttons.o irq.o led.o reset.o rtc.o serial.o setup.o obj-y := buttons.o irq.o led.o reset.o rtc.o serial.o setup.o time.o
obj-$(CONFIG_PCI) += pci.o obj-$(CONFIG_PCI) += pci.o
obj-$(CONFIG_EARLY_PRINTK) += console.o obj-$(CONFIG_EARLY_PRINTK) += console.o
......
...@@ -9,19 +9,17 @@ ...@@ -9,19 +9,17 @@
* Copyright (C) 2001, 2002, 2003 by Liam Davies (ldavies@agile.tv) * Copyright (C) 2001, 2002, 2003 by Liam Davies (ldavies@agile.tv)
* *
*/ */
#include <linux/interrupt.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/ioport.h>
#include <linux/pm.h> #include <linux/pm.h>
#include <asm/bootinfo.h> #include <asm/bootinfo.h>
#include <asm/time.h>
#include <asm/i8253.h>
#include <asm/io.h>
#include <asm/reboot.h> #include <asm/reboot.h>
#include <asm/gt64120.h> #include <asm/gt64120.h>
#include <cobalt.h> #include <cobalt.h>
#include <irq.h>
extern void cobalt_machine_restart(char *command); extern void cobalt_machine_restart(char *command);
extern void cobalt_machine_halt(void); extern void cobalt_machine_halt(void);
...@@ -41,17 +39,6 @@ const char *get_system_type(void) ...@@ -41,17 +39,6 @@ const char *get_system_type(void)
return "MIPS Cobalt"; return "MIPS Cobalt";
} }
void __init plat_timer_setup(struct irqaction *irq)
{
/* Load timer value for HZ (TCLK is 50MHz) */
GT_WRITE(GT_TC0_OFS, 50*1000*1000 / HZ);
/* Enable timer0 */
GT_WRITE(GT_TC_CONTROL_OFS, GT_TC_CONTROL_ENTC0_MSK | GT_TC_CONTROL_SELTC0_MSK);
setup_irq(GT641XX_TIMER0_IRQ, irq);
}
/* /*
* Cobalt doesn't have PS/2 keyboard/mouse interfaces, * Cobalt doesn't have PS/2 keyboard/mouse interfaces,
* keyboard conntroller is never used. * keyboard conntroller is never used.
...@@ -84,11 +71,6 @@ static struct resource cobalt_reserved_resources[] = { ...@@ -84,11 +71,6 @@ static struct resource cobalt_reserved_resources[] = {
}, },
}; };
void __init plat_time_init(void)
{
setup_pit_timer();
}
void __init plat_mem_setup(void) void __init plat_mem_setup(void)
{ {
int i; int i;
......
/*
* Cobalt time initialization.
*
* Copyright (C) 2007 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
*
* 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.
*
* This program is distributed in the hope that 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <linux/init.h>
#include <asm/gt64120.h>
#include <asm/i8253.h>
#include <asm/time.h>
#define GT641XX_BASE_CLOCK 50000000 /* 50MHz */
void __init plat_time_init(void)
{
setup_pit_timer();
gt641xx_set_base_clock(GT641XX_BASE_CLOCK);
mips_timer_state = gt641xx_timer0_state;
}
...@@ -9,6 +9,7 @@ obj-y += cpu-probe.o branch.o entry.o genex.o irq.o process.o \ ...@@ -9,6 +9,7 @@ obj-y += cpu-probe.o branch.o entry.o genex.o irq.o process.o \
time.o topology.o traps.o unaligned.o time.o topology.o traps.o unaligned.o
obj-$(CONFIG_CEVT_R4K) += cevt-r4k.o obj-$(CONFIG_CEVT_R4K) += cevt-r4k.o
obj-$(CONFIG_CEVT_GT641XX) += cevt-gt641xx.o
binfmt_irix-objs := irixelf.o irixinv.o irixioctl.o irixsig.o \ binfmt_irix-objs := irixelf.o irixinv.o irixioctl.o irixsig.o \
irix5sys.o sysirix.o irix5sys.o sysirix.o
......
/*
* GT641xx clockevent routines.
*
* Copyright (C) 2007 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
*
* 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.
*
* This program is distributed in the hope that 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <linux/clockchips.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/spinlock.h>
#include <asm/gt64120.h>
#include <asm/time.h>
#include <irq.h>
static DEFINE_SPINLOCK(gt641xx_timer_lock);
static unsigned int gt641xx_base_clock;
void gt641xx_set_base_clock(unsigned int clock)
{
gt641xx_base_clock = clock;
}
int gt641xx_timer0_state(void)
{
if (GT_READ(GT_TC0_OFS))
return 0;
GT_WRITE(GT_TC0_OFS, gt641xx_base_clock / HZ);
GT_WRITE(GT_TC_CONTROL_OFS, GT_TC_CONTROL_ENTC0_MSK);
return 1;
}
static int gt641xx_timer0_set_next_event(unsigned long delta,
struct clock_event_device *evt)
{
unsigned long flags;
u32 ctrl;
spin_lock_irqsave(&gt641xx_timer_lock, flags);
ctrl = GT_READ(GT_TC_CONTROL_OFS);
ctrl &= ~(GT_TC_CONTROL_ENTC0_MSK | GT_TC_CONTROL_SELTC0_MSK);
ctrl |= GT_TC_CONTROL_ENTC0_MSK;
GT_WRITE(GT_TC0_OFS, delta);
GT_WRITE(GT_TC_CONTROL_OFS, ctrl);
spin_unlock_irqrestore(&gt641xx_timer_lock, flags);
return 0;
}
static void gt641xx_timer0_set_mode(enum clock_event_mode mode,
struct clock_event_device *evt)
{
unsigned long flags;
u32 ctrl;
spin_lock_irqsave(&gt641xx_timer_lock, flags);
ctrl = GT_READ(GT_TC_CONTROL_OFS);
ctrl &= ~(GT_TC_CONTROL_ENTC0_MSK | GT_TC_CONTROL_SELTC0_MSK);
switch (mode) {
case CLOCK_EVT_MODE_PERIODIC:
ctrl |= GT_TC_CONTROL_ENTC0_MSK | GT_TC_CONTROL_SELTC0_MSK;
break;
case CLOCK_EVT_MODE_ONESHOT:
ctrl |= GT_TC_CONTROL_ENTC0_MSK;
break;
default:
break;
}
GT_WRITE(GT_TC_CONTROL_OFS, ctrl);
spin_unlock_irqrestore(&gt641xx_timer_lock, flags);
}
static void gt641xx_timer0_event_handler(struct clock_event_device *dev)
{
}
static struct clock_event_device gt641xx_timer0_clockevent = {
.name = "gt641xx-timer0",
.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
.cpumask = CPU_MASK_CPU0,
.irq = GT641XX_TIMER0_IRQ,
.set_next_event = gt641xx_timer0_set_next_event,
.set_mode = gt641xx_timer0_set_mode,
.event_handler = gt641xx_timer0_event_handler,
};
static irqreturn_t gt641xx_timer0_interrupt(int irq, void *dev_id)
{
struct clock_event_device *cd = &gt641xx_timer0_clockevent;
cd->event_handler(cd);
return IRQ_HANDLED;
}
static struct irqaction gt641xx_timer0_irqaction = {
.handler = gt641xx_timer0_interrupt,
.flags = IRQF_DISABLED | IRQF_PERCPU,
.name = "gt641xx_timer0",
};
static int __init gt641xx_timer0_clockevent_init(void)
{
struct clock_event_device *cd;
if (!gt641xx_base_clock)
return 0;
GT_WRITE(GT_TC0_OFS, gt641xx_base_clock / HZ);
cd = &gt641xx_timer0_clockevent;
cd->rating = 200 + gt641xx_base_clock / 10000000;
cd->max_delta_ns = clockevent_delta2ns(0x7fffffff, cd);
cd->min_delta_ns = clockevent_delta2ns(0x300, cd);
clockevent_set_clock(cd, gt641xx_base_clock);
clockevents_register_device(&gt641xx_timer0_clockevent);
return setup_irq(GT641XX_TIMER0_IRQ, &gt641xx_timer0_irqaction);
}
arch_initcall(gt641xx_timer0_clockevent_init);
...@@ -186,7 +186,7 @@ static int c0_compare_int_usable(void) ...@@ -186,7 +186,7 @@ static int c0_compare_int_usable(void)
* IP7 already pending? Try to clear it by acking the timer. * IP7 already pending? Try to clear it by acking the timer.
*/ */
if (c0_compare_int_pending()) { if (c0_compare_int_pending()) {
write_c0_compare(read_c0_compare()); write_c0_compare(read_c0_count());
irq_disable_hazard(); irq_disable_hazard();
if (c0_compare_int_pending()) if (c0_compare_int_pending())
return 0; return 0;
...@@ -202,7 +202,7 @@ static int c0_compare_int_usable(void) ...@@ -202,7 +202,7 @@ static int c0_compare_int_usable(void)
if (!c0_compare_int_pending()) if (!c0_compare_int_pending())
return 0; return 0;
write_c0_compare(read_c0_compare()); write_c0_compare(read_c0_count());
irq_disable_hazard(); irq_disable_hazard();
if (c0_compare_int_pending()) if (c0_compare_int_pending())
return 0; return 0;
......
...@@ -195,8 +195,8 @@ void __cpuinit clockevent_set_clock(struct clock_event_device *cd, ...@@ -195,8 +195,8 @@ void __cpuinit clockevent_set_clock(struct clock_event_device *cd,
/* Find a shift value */ /* Find a shift value */
for (shift = 32; shift > 0; shift--) { for (shift = 32; shift > 0; shift--) {
temp = (u64) NSEC_PER_SEC << shift; temp = (u64) clock << shift;
do_div(temp, clock); do_div(temp, NSEC_PER_SEC);
if ((temp >> 32) == 0) if ((temp >> 32) == 0)
break; break;
} }
......
...@@ -147,21 +147,8 @@ void __init plat_time_init(void) ...@@ -147,21 +147,8 @@ void __init plat_time_init(void)
#endif #endif
} }
//static irqreturn_t mips_perf_interrupt(int irq, void *dev_id)
//{
// return perf_irq();
//}
//static struct irqaction perf_irqaction = {
// .handler = mips_perf_interrupt,
// .flags = IRQF_DISABLED | IRQF_PERCPU,
// .name = "performance",
//};
void __init plat_perf_setup(void) void __init plat_perf_setup(void)
{ {
// struct irqaction *irq = &perf_irqaction;
cp0_perfcount_irq = -1; cp0_perfcount_irq = -1;
#ifdef MSC01E_INT_BASE #ifdef MSC01E_INT_BASE
......
...@@ -110,7 +110,7 @@ static void __init per_hub_init(cnodeid_t cnode) ...@@ -110,7 +110,7 @@ static void __init per_hub_init(cnodeid_t cnode)
} }
} }
void __init per_cpu_init(void) void __cpuinit per_cpu_init(void)
{ {
int cpu = smp_processor_id(); int cpu = smp_processor_id();
int slice = LOCAL_HUB_L(PI_CPU_NUM); int slice = LOCAL_HUB_L(PI_CPU_NUM);
......
...@@ -111,8 +111,24 @@ unsigned long read_persistent_clock(void) ...@@ -111,8 +111,24 @@ unsigned long read_persistent_clock(void)
return mktime(year, month, date, hour, min, sec); return mktime(year, month, date, hour, min, sec);
} }
static int rt_set_next_event(unsigned long delta, static void enable_rt_irq(unsigned int irq)
struct clock_event_device *evt) {
}
static void disable_rt_irq(unsigned int irq)
{
}
static struct irq_chip rt_irq_type = {
.name = "SN HUB RT timer",
.ack = disable_rt_irq,
.mask = disable_rt_irq,
.mask_ack = disable_rt_irq,
.unmask = enable_rt_irq,
.eoi = enable_rt_irq,
};
static int rt_next_event(unsigned long delta, struct clock_event_device *evt)
{ {
unsigned int cpu = smp_processor_id(); unsigned int cpu = smp_processor_id();
int slice = cputoslice(cpu) == 0; int slice = cputoslice(cpu) == 0;
...@@ -129,50 +145,24 @@ static void rt_set_mode(enum clock_event_mode mode, ...@@ -129,50 +145,24 @@ static void rt_set_mode(enum clock_event_mode mode,
struct clock_event_device *evt) struct clock_event_device *evt)
{ {
switch (mode) { switch (mode) {
case CLOCK_EVT_MODE_PERIODIC: case CLOCK_EVT_MODE_ONESHOT:
/* The only mode supported */ /* The only mode supported */
break; break;
case CLOCK_EVT_MODE_PERIODIC:
case CLOCK_EVT_MODE_UNUSED: case CLOCK_EVT_MODE_UNUSED:
case CLOCK_EVT_MODE_SHUTDOWN: case CLOCK_EVT_MODE_SHUTDOWN:
case CLOCK_EVT_MODE_ONESHOT:
case CLOCK_EVT_MODE_RESUME: case CLOCK_EVT_MODE_RESUME:
/* Nothing to do */ /* Nothing to do */
break; break;
} }
} }
struct clock_event_device rt_clock_event_device = {
.name = "HUB-RT",
.features = CLOCK_EVT_FEAT_ONESHOT,
.rating = 300,
.set_next_event = rt_set_next_event,
.set_mode = rt_set_mode,
};
static void enable_rt_irq(unsigned int irq)
{
}
static void disable_rt_irq(unsigned int irq)
{
}
static struct irq_chip rt_irq_type = {
.name = "SN HUB RT timer",
.ack = disable_rt_irq,
.mask = disable_rt_irq,
.mask_ack = disable_rt_irq,
.unmask = enable_rt_irq,
.eoi = enable_rt_irq,
};
unsigned int rt_timer_irq; unsigned int rt_timer_irq;
static irqreturn_t ip27_rt_timer_interrupt(int irq, void *dev_id) static irqreturn_t hub_rt_counter_handler(int irq, void *dev_id)
{ {
struct clock_event_device *cd = &rt_clock_event_device; struct clock_event_device *cd = dev_id;
unsigned int cpu = smp_processor_id(); unsigned int cpu = smp_processor_id();
int slice = cputoslice(cpu) == 0; int slice = cputoslice(cpu) == 0;
...@@ -182,11 +172,10 @@ static irqreturn_t ip27_rt_timer_interrupt(int irq, void *dev_id) ...@@ -182,11 +172,10 @@ static irqreturn_t ip27_rt_timer_interrupt(int irq, void *dev_id)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
static struct irqaction rt_irqaction = { struct irqaction hub_rt_irqaction = {
.handler = (irq_handler_t) ip27_rt_timer_interrupt, .handler = hub_rt_counter_handler,
.flags = IRQF_DISABLED, .flags = IRQF_DISABLED | IRQF_PERCPU,
.mask = CPU_MASK_NONE, .name = "hub-rt",
.name = "timer"
}; };
/* /*
...@@ -200,32 +189,48 @@ static struct irqaction rt_irqaction = { ...@@ -200,32 +189,48 @@ static struct irqaction rt_irqaction = {
#define NSEC_PER_CYCLE 800 #define NSEC_PER_CYCLE 800
#define CYCLES_PER_SEC (NSEC_PER_SEC / NSEC_PER_CYCLE) #define CYCLES_PER_SEC (NSEC_PER_SEC / NSEC_PER_CYCLE)
static void __init ip27_rt_clock_event_init(void) static DEFINE_PER_CPU(struct clock_event_device, hub_rt_clockevent);
static DEFINE_PER_CPU(char [11], hub_rt_name);
static void __cpuinit hub_rt_clock_event_init(void)
{ {
struct clock_event_device *cd = &rt_clock_event_device;
unsigned int cpu = smp_processor_id(); unsigned int cpu = smp_processor_id();
int irq = allocate_irqno(); struct clock_event_device *cd = &per_cpu(hub_rt_clockevent, cpu);
unsigned char *name = per_cpu(hub_rt_name, cpu);
if (irq < 0) int irq = rt_timer_irq;
panic("Can't allocate interrupt number for timer interrupt");
sprintf(name, "hub-rt %d", cpu);
rt_timer_irq = irq; cd->name = "HUB-RT",
cd->features = CLOCK_EVT_FEAT_ONESHOT,
clockevent_set_clock(cd, CYCLES_PER_SEC);
cd->max_delta_ns = clockevent_delta2ns(0xfffffffffffff, cd);
cd->min_delta_ns = clockevent_delta2ns(0x300, cd);
cd->rating = 200,
cd->irq = irq, cd->irq = irq,
cd->cpumask = cpumask_of_cpu(cpu), cd->cpumask = cpumask_of_cpu(cpu),
cd->rating = 300,
/* cd->set_next_event = rt_next_event,
* Calculate the min / max delta cd->set_mode = rt_set_mode,
*/
cd->mult =
div_sc((unsigned long) CYCLES_PER_SEC, NSEC_PER_SEC, 32);
cd->shift = 32;
cd->max_delta_ns = clockevent_delta2ns(0x7fffffff, cd);
cd->min_delta_ns = clockevent_delta2ns(0x300, cd);
clockevents_register_device(cd); clockevents_register_device(cd);
}
static void __init hub_rt_clock_event_global_init(void)
{
unsigned int irq;
do {
smp_wmb();
irq = rt_timer_irq;
if (irq)
break;
irq = allocate_irqno();
if (irq < 0)
panic("Allocation of irq number for timer failed");
} while (xchg(&rt_timer_irq, irq));
set_irq_chip_and_handler(irq, &rt_irq_type, handle_percpu_irq); set_irq_chip_and_handler(irq, &rt_irq_type, handle_percpu_irq);
setup_irq(irq, &rt_irqaction); setup_irq(irq, &hub_rt_irqaction);
} }
static cycle_t hub_rt_read(void) static cycle_t hub_rt_read(void)
...@@ -233,27 +238,29 @@ static cycle_t hub_rt_read(void) ...@@ -233,27 +238,29 @@ static cycle_t hub_rt_read(void)
return REMOTE_HUB_L(cputonasid(0), PI_RT_COUNT); return REMOTE_HUB_L(cputonasid(0), PI_RT_COUNT);
} }
struct clocksource ht_rt_clocksource = { struct clocksource hub_rt_clocksource = {
.name = "HUB-RT", .name = "HUB-RT",
.rating = 200, .rating = 200,
.read = hub_rt_read, .read = hub_rt_read,
.mask = CLOCKSOURCE_MASK(52), .mask = CLOCKSOURCE_MASK(52),
.shift = 32,
.flags = CLOCK_SOURCE_IS_CONTINUOUS, .flags = CLOCK_SOURCE_IS_CONTINUOUS,
}; };
static void __init ip27_rt_clocksource_init(void) static void __init hub_rt_clocksource_init(void)
{ {
clocksource_register(&ht_rt_clocksource); struct clocksource *cs = &hub_rt_clocksource;
clocksource_set_clock(cs, CYCLES_PER_SEC);
clocksource_register(cs);
} }
void __init plat_time_init(void) void __init plat_time_init(void)
{ {
ip27_rt_clock_event_init(); hub_rt_clocksource_init();
ip27_rt_clocksource_init(); hub_rt_clock_event_global_init();
} }
void __init cpu_time_init(void) void __cpuinit cpu_time_init(void)
{ {
lboard_t *board; lboard_t *board;
klcpu_t *cpu; klcpu_t *cpu;
...@@ -271,6 +278,7 @@ void __init cpu_time_init(void) ...@@ -271,6 +278,7 @@ void __init cpu_time_init(void)
printk("CPU %d clock is %dMHz.\n", smp_processor_id(), cpu->cpu_speed); printk("CPU %d clock is %dMHz.\n", smp_processor_id(), cpu->cpu_speed);
hub_rt_clock_event_init();
set_c0_status(SRB_TIMOCLK); set_c0_status(SRB_TIMOCLK);
} }
......
...@@ -452,6 +452,43 @@ static void bcm1480_kgdb_interrupt(void) ...@@ -452,6 +452,43 @@ static void bcm1480_kgdb_interrupt(void)
extern void bcm1480_mailbox_interrupt(void); extern void bcm1480_mailbox_interrupt(void);
static inline void dispatch_ip4(void)
{
int cpu = smp_processor_id();
int irq = K_BCM1480_INT_TIMER_0 + cpu;
/* Reset the timer */
__raw_writeq(M_SCD_TIMER_ENABLE|M_SCD_TIMER_MODE_CONTINUOUS,
IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG)));
do_IRQ(irq);
}
static inline void dispatch_ip2(void)
{
unsigned long long mask_h, mask_l;
unsigned int cpu = smp_processor_id();
unsigned long base;
/*
* Default...we've hit an IP[2] interrupt, which means we've got to
* check the 1480 interrupt registers to figure out what to do. Need
* to detect which CPU we're on, now that smp_affinity is supported.
*/
base = A_BCM1480_IMR_MAPPER(cpu);
mask_h = __raw_readq(
IOADDR(base + R_BCM1480_IMR_INTERRUPT_STATUS_BASE_H));
mask_l = __raw_readq(
IOADDR(base + R_BCM1480_IMR_INTERRUPT_STATUS_BASE_L));
if (mask_h) {
if (mask_h ^ 1)
do_IRQ(fls64(mask_h) - 1);
else if (mask_l)
do_IRQ(63 + fls64(mask_l));
}
}
asmlinkage void plat_irq_dispatch(void) asmlinkage void plat_irq_dispatch(void)
{ {
unsigned int pending; unsigned int pending;
...@@ -469,17 +506,8 @@ asmlinkage void plat_irq_dispatch(void) ...@@ -469,17 +506,8 @@ asmlinkage void plat_irq_dispatch(void)
else else
#endif #endif
if (pending & CAUSEF_IP4) { if (pending & CAUSEF_IP4)
int cpu = smp_processor_id(); dispatch_ip4();
int irq = K_BCM1480_INT_TIMER_0 + cpu;
/* Reset the timer */
__raw_writeq(M_SCD_TIMER_ENABLE|M_SCD_TIMER_MODE_CONTINUOUS,
IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG)));
do_IRQ(irq);
}
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
else if (pending & CAUSEF_IP3) else if (pending & CAUSEF_IP3)
bcm1480_mailbox_interrupt(); bcm1480_mailbox_interrupt();
...@@ -490,27 +518,6 @@ asmlinkage void plat_irq_dispatch(void) ...@@ -490,27 +518,6 @@ asmlinkage void plat_irq_dispatch(void)
bcm1480_kgdb_interrupt(); /* KGDB (uart 1) */ bcm1480_kgdb_interrupt(); /* KGDB (uart 1) */
#endif #endif
else if (pending & CAUSEF_IP2) { else if (pending & CAUSEF_IP2)
unsigned long long mask_h, mask_l; dispatch_ip2();
unsigned long base;
/*
* Default...we've hit an IP[2] interrupt, which means we've
* got to check the 1480 interrupt registers to figure out what
* to do. Need to detect which CPU we're on, now that
* smp_affinity is supported.
*/
base = A_BCM1480_IMR_MAPPER(smp_processor_id());
mask_h = __raw_readq(
IOADDR(base + R_BCM1480_IMR_INTERRUPT_STATUS_BASE_H));
mask_l = __raw_readq(
IOADDR(base + R_BCM1480_IMR_INTERRUPT_STATUS_BASE_L));
if (mask_h) {
if (mask_h ^ 1)
do_IRQ(fls64(mask_h) - 1);
else
do_IRQ(63 + fls64(mask_l));
}
}
} }
...@@ -58,7 +58,7 @@ static void *mailbox_0_regs[] = { ...@@ -58,7 +58,7 @@ static void *mailbox_0_regs[] = {
/* /*
* SMP init and finish on secondary CPUs * SMP init and finish on secondary CPUs
*/ */
void bcm1480_smp_init(void) void __cpuinit bcm1480_smp_init(void)
{ {
unsigned int imask = STATUSF_IP4 | STATUSF_IP3 | STATUSF_IP2 | unsigned int imask = STATUSF_IP4 | STATUSF_IP3 | STATUSF_IP2 |
STATUSF_IP1 | STATUSF_IP0; STATUSF_IP1 | STATUSF_IP0;
...@@ -67,7 +67,7 @@ void bcm1480_smp_init(void) ...@@ -67,7 +67,7 @@ void bcm1480_smp_init(void)
change_c0_status(ST0_IM, imask); change_c0_status(ST0_IM, imask);
} }
void bcm1480_smp_finish(void) void __cpuinit bcm1480_smp_finish(void)
{ {
extern void sb1480_clockevent_init(void); extern void sb1480_clockevent_init(void);
......
...@@ -15,22 +15,12 @@ ...@@ -15,22 +15,12 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/ */
/*
* These are routines to set up and handle interrupts from the
* bcm1480 general purpose timer 0. We're using the timer as a
* system clock, so we set it up to run at 100 Hz. On every
* interrupt, we update our idea of what the time of day is,
* then call do_timer() in the architecture-independent kernel
* code to do general bookkeeping (e.g. update jiffies, run
* bottom halves, etc.)
*/
#include <linux/clockchips.h> #include <linux/clockchips.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/percpu.h> #include <linux/percpu.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <asm/irq.h>
#include <asm/addrspace.h> #include <asm/addrspace.h>
#include <asm/time.h> #include <asm/time.h>
#include <asm/io.h> #include <asm/io.h>
...@@ -47,33 +37,10 @@ ...@@ -47,33 +37,10 @@
#define IMR_IP3_VAL K_BCM1480_INT_MAP_I1 #define IMR_IP3_VAL K_BCM1480_INT_MAP_I1
#define IMR_IP4_VAL K_BCM1480_INT_MAP_I2 #define IMR_IP4_VAL K_BCM1480_INT_MAP_I2
#ifdef CONFIG_SIMULATION
#define BCM1480_HPT_VALUE 50000
#else
#define BCM1480_HPT_VALUE 1000000
#endif
extern int bcm1480_steal_irq(int irq); extern int bcm1480_steal_irq(int irq);
void __init plat_time_init(void)
{
unsigned int cpu = smp_processor_id();
unsigned int irq = K_BCM1480_INT_TIMER_0 + cpu;
BUG_ON(cpu > 3); /* Only have 4 general purpose timers */
bcm1480_mask_irq(cpu, irq);
/* Map the timer interrupt to ip[4] of this cpu */
__raw_writeq(IMR_IP4_VAL, IOADDR(A_BCM1480_IMR_REGISTER(cpu, R_BCM1480_IMR_INTERRUPT_MAP_BASE_H)
+ (irq<<3)));
bcm1480_unmask_irq(cpu, irq);
bcm1480_steal_irq(irq);
}
/* /*
* The general purpose timer ticks at 1 Mhz independent if * The general purpose timer ticks at 1MHz independent if
* the rest of the system * the rest of the system
*/ */
static void sibyte_set_mode(enum clock_event_mode mode, static void sibyte_set_mode(enum clock_event_mode mode,
...@@ -88,7 +55,7 @@ static void sibyte_set_mode(enum clock_event_mode mode, ...@@ -88,7 +55,7 @@ static void sibyte_set_mode(enum clock_event_mode mode,
switch (mode) { switch (mode) {
case CLOCK_EVT_MODE_PERIODIC: case CLOCK_EVT_MODE_PERIODIC:
__raw_writeq(0, timer_cfg); __raw_writeq(0, timer_cfg);
__raw_writeq(BCM1480_HPT_VALUE / HZ - 1, timer_init); __raw_writeq((V_SCD_TIMER_FREQ / HZ) - 1, timer_init);
__raw_writeq(M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS, __raw_writeq(M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS,
timer_cfg); timer_cfg);
break; break;
...@@ -121,80 +88,96 @@ static int sibyte_next_event(unsigned long delta, struct clock_event_device *cd) ...@@ -121,80 +88,96 @@ static int sibyte_next_event(unsigned long delta, struct clock_event_device *cd)
return res; return res;
} }
static DEFINE_PER_CPU(struct clock_event_device, sibyte_hpt_clockevent);
static irqreturn_t sibyte_counter_handler(int irq, void *dev_id) static irqreturn_t sibyte_counter_handler(int irq, void *dev_id)
{ {
unsigned int cpu = smp_processor_id(); unsigned int cpu = smp_processor_id();
struct clock_event_device *cd = &per_cpu(sibyte_hpt_clockevent, cpu); struct clock_event_device *cd = dev_id;
void __iomem *timer_cfg;
timer_cfg = IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG));
/* Reset the timer */ /* Reset the timer */
__raw_writeq(M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS, __raw_writeq(M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS,
IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG))); timer_cfg);
cd->event_handler(cd); cd->event_handler(cd);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
static struct irqaction sibyte_counter_irqaction = { static DEFINE_PER_CPU(struct clock_event_device, sibyte_hpt_clockevent);
.handler = sibyte_counter_handler, static DEFINE_PER_CPU(struct irqaction, sibyte_hpt_irqaction);
.flags = IRQF_DISABLED | IRQF_PERCPU, static DEFINE_PER_CPU(char [18], sibyte_hpt_name);
.name = "timer",
};
/*
* This interrupt is "special" in that it doesn't use the request_irq
* way to hook the irq line. The timer interrupt is initialized early
* enough to make this a major pain, and it's also firing enough to
* warrant a bit of special case code. bcm1480_timer_interrupt is
* called directly from irq_handler.S when IP[4] is set during an
* interrupt
*/
void __cpuinit sb1480_clockevent_init(void) void __cpuinit sb1480_clockevent_init(void)
{ {
unsigned int cpu = smp_processor_id(); unsigned int cpu = smp_processor_id();
unsigned int irq = K_BCM1480_INT_TIMER_0 + cpu; unsigned int irq = K_BCM1480_INT_TIMER_0 + cpu;
struct irqaction *action = &per_cpu(sibyte_hpt_irqaction, cpu);
struct clock_event_device *cd = &per_cpu(sibyte_hpt_clockevent, cpu); struct clock_event_device *cd = &per_cpu(sibyte_hpt_clockevent, cpu);
unsigned char *name = per_cpu(sibyte_hpt_name, cpu);
BUG_ON(cpu > 3); /* Only have 4 general purpose timers */
cd->name = "bcm1480-counter"; sprintf(name, "bcm1480-counter %d", cpu);
cd->name = name;
cd->features = CLOCK_EVT_FEAT_PERIODIC | cd->features = CLOCK_EVT_FEAT_PERIODIC |
CLOCK_EVT_MODE_ONESHOT; CLOCK_EVT_MODE_ONESHOT;
clockevent_set_clock(cd, V_SCD_TIMER_FREQ);
cd->max_delta_ns = clockevent_delta2ns(0x7fffff, cd);
cd->min_delta_ns = clockevent_delta2ns(1, cd);
cd->rating = 200;
cd->irq = irq;
cd->cpumask = cpumask_of_cpu(cpu);
cd->set_next_event = sibyte_next_event; cd->set_next_event = sibyte_next_event;
cd->set_mode = sibyte_set_mode; cd->set_mode = sibyte_set_mode;
cd->irq = irq; clockevents_register_device(cd);
clockevent_set_clock(cd, BCM1480_HPT_VALUE);
bcm1480_mask_irq(cpu, irq);
/*
* Map timer interrupt to IP[4] of this cpu
*/
__raw_writeq(IMR_IP4_VAL,
IOADDR(A_BCM1480_IMR_REGISTER(cpu,
R_BCM1480_IMR_INTERRUPT_MAP_BASE_H) + (irq << 3)));
setup_irq(irq, &sibyte_counter_irqaction); bcm1480_unmask_irq(cpu, irq);
bcm1480_steal_irq(irq);
action->handler = sibyte_counter_handler;
action->flags = IRQF_DISABLED | IRQF_PERCPU;
action->name = name;
action->dev_id = cd;
setup_irq(irq, action);
} }
static cycle_t bcm1480_hpt_read(void) static cycle_t bcm1480_hpt_read(void)
{ {
/* We assume this function is called xtime_lock held. */ return (cycle_t) __raw_readq(IOADDR(A_SCD_ZBBUS_CYCLE_COUNT));
unsigned long count =
__raw_readq(IOADDR(A_SCD_TIMER_REGISTER(0, R_SCD_TIMER_CNT)));
return (jiffies + 1) * (BCM1480_HPT_VALUE / HZ) - count;
} }
struct clocksource bcm1480_clocksource = { struct clocksource bcm1480_clocksource = {
.name = "MIPS", .name = "zbbus-cycles",
.rating = 200, .rating = 200,
.read = bcm1480_hpt_read, .read = bcm1480_hpt_read,
.mask = CLOCKSOURCE_MASK(32), .mask = CLOCKSOURCE_MASK(64),
.shift = 32,
.flags = CLOCK_SOURCE_IS_CONTINUOUS, .flags = CLOCK_SOURCE_IS_CONTINUOUS,
}; };
void __init sb1480_clocksource_init(void) void __init sb1480_clocksource_init(void)
{ {
struct clocksource *cs = &bcm1480_clocksource; struct clocksource *cs = &bcm1480_clocksource;
unsigned int plldiv;
unsigned long zbbus;
clocksource_set_clock(cs, BCM1480_HPT_VALUE); plldiv = G_BCM1480_SYS_PLL_DIV(__raw_readq(IOADDR(A_SCD_SYSTEM_CFG)));
zbbus = ((plldiv >> 1) * 50000000) + ((plldiv & 1) * 25000000);
clocksource_set_clock(cs, zbbus);
clocksource_register(cs); clocksource_register(cs);
} }
void __init bcm1480_hpt_setup(void) void __init plat_time_init(void)
{ {
mips_hpt_frequency = BCM1480_HPT_VALUE;
sb1480_clocksource_init(); sb1480_clocksource_init();
sb1480_clockevent_init(); sb1480_clockevent_init();
} }
...@@ -402,6 +402,22 @@ static void sb1250_kgdb_interrupt(void) ...@@ -402,6 +402,22 @@ static void sb1250_kgdb_interrupt(void)
extern void sb1250_mailbox_interrupt(void); extern void sb1250_mailbox_interrupt(void);
static inline void dispatch_ip2(void)
{
unsigned int cpu = smp_processor_id();
unsigned long long mask;
/*
* Default...we've hit an IP[2] interrupt, which means we've got to
* check the 1250 interrupt registers to figure out what to do. Need
* to detect which CPU we're on, now that smp_affinity is supported.
*/
mask = __raw_readq(IOADDR(A_IMR_REGISTER(cpu,
R_IMR_INTERRUPT_STATUS_BASE)));
if (mask)
do_IRQ(fls64(mask) - 1);
}
asmlinkage void plat_irq_dispatch(void) asmlinkage void plat_irq_dispatch(void)
{ {
unsigned int cpu = smp_processor_id(); unsigned int cpu = smp_processor_id();
...@@ -434,21 +450,8 @@ asmlinkage void plat_irq_dispatch(void) ...@@ -434,21 +450,8 @@ asmlinkage void plat_irq_dispatch(void)
sb1250_kgdb_interrupt(); sb1250_kgdb_interrupt();
#endif #endif
else if (pending & CAUSEF_IP2) { else if (pending & CAUSEF_IP2)
unsigned long long mask; dispatch_ip2();
else
/*
* Default...we've hit an IP[2] interrupt, which means we've
* got to check the 1250 interrupt registers to figure out what
* to do. Need to detect which CPU we're on, now that
* smp_affinity is supported.
*/
mask = __raw_readq(IOADDR(A_IMR_REGISTER(smp_processor_id(),
R_IMR_INTERRUPT_STATUS_BASE)));
if (mask)
do_IRQ(fls64(mask) - 1);
else
spurious_interrupt();
} else
spurious_interrupt(); spurious_interrupt();
} }
...@@ -46,7 +46,7 @@ static void *mailbox_regs[] = { ...@@ -46,7 +46,7 @@ static void *mailbox_regs[] = {
/* /*
* SMP init and finish on secondary CPUs * SMP init and finish on secondary CPUs
*/ */
void sb1250_smp_init(void) void __cpuinit sb1250_smp_init(void)
{ {
unsigned int imask = STATUSF_IP4 | STATUSF_IP3 | STATUSF_IP2 | unsigned int imask = STATUSF_IP4 | STATUSF_IP3 | STATUSF_IP2 |
STATUSF_IP1 | STATUSF_IP0; STATUSF_IP1 | STATUSF_IP0;
...@@ -55,7 +55,7 @@ void sb1250_smp_init(void) ...@@ -55,7 +55,7 @@ void sb1250_smp_init(void)
change_c0_status(ST0_IM, imask); change_c0_status(ST0_IM, imask);
} }
void sb1250_smp_finish(void) void __cpuinit sb1250_smp_finish(void)
{ {
extern void sb1250_clockevent_init(void); extern void sb1250_clockevent_init(void);
......
...@@ -52,26 +52,6 @@ ...@@ -52,26 +52,6 @@
extern int sb1250_steal_irq(int irq); extern int sb1250_steal_irq(int irq);
static cycle_t sb1250_hpt_read(void);
void __init sb1250_hpt_setup(void)
{
int cpu = smp_processor_id();
if (!cpu) {
/* Setup hpt using timer #3 but do not enable irq for it */
__raw_writeq(0, IOADDR(A_SCD_TIMER_REGISTER(SB1250_HPT_NUM, R_SCD_TIMER_CFG)));
__raw_writeq(SB1250_HPT_VALUE,
IOADDR(A_SCD_TIMER_REGISTER(SB1250_HPT_NUM, R_SCD_TIMER_INIT)));
__raw_writeq(M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS,
IOADDR(A_SCD_TIMER_REGISTER(SB1250_HPT_NUM, R_SCD_TIMER_CFG)));
mips_hpt_frequency = V_SCD_TIMER_FREQ;
clocksource_mips.read = sb1250_hpt_read;
clocksource_mips.mask = M_SCD_TIMER_INIT;
}
}
/* /*
* The general purpose timer ticks at 1 Mhz independent if * The general purpose timer ticks at 1 Mhz independent if
* the rest of the system * the rest of the system
...@@ -121,18 +101,14 @@ sibyte_next_event(unsigned long delta, struct clock_event_device *evt) ...@@ -121,18 +101,14 @@ sibyte_next_event(unsigned long delta, struct clock_event_device *evt)
return 0; return 0;
} }
struct clock_event_device sibyte_hpt_clockevent = {
.name = "sb1250-counter",
.features = CLOCK_EVT_FEAT_PERIODIC,
.set_mode = sibyte_set_mode,
.set_next_event = sibyte_next_event,
.shift = 32,
.irq = 0,
};
static irqreturn_t sibyte_counter_handler(int irq, void *dev_id) static irqreturn_t sibyte_counter_handler(int irq, void *dev_id)
{ {
struct clock_event_device *cd = &sibyte_hpt_clockevent; unsigned int cpu = smp_processor_id();
struct clock_event_device *cd = dev_id;
/* ACK interrupt */
____raw_writeq(M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS,
IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG)));
cd->event_handler(cd); cd->event_handler(cd);
...@@ -145,15 +121,35 @@ static struct irqaction sibyte_irqaction = { ...@@ -145,15 +121,35 @@ static struct irqaction sibyte_irqaction = {
.name = "timer", .name = "timer",
}; };
static DEFINE_PER_CPU(struct clock_event_device, sibyte_hpt_clockevent);
static DEFINE_PER_CPU(struct irqaction, sibyte_hpt_irqaction);
static DEFINE_PER_CPU(char [18], sibyte_hpt_name);
void __cpuinit sb1250_clockevent_init(void) void __cpuinit sb1250_clockevent_init(void)
{ {
struct clock_event_device *cd = &sibyte_hpt_clockevent;
unsigned int cpu = smp_processor_id(); unsigned int cpu = smp_processor_id();
int irq = K_INT_TIMER_0 + cpu; unsigned int irq = K_INT_TIMER_0 + cpu;
struct irqaction *action = &per_cpu(sibyte_hpt_irqaction, cpu);
struct clock_event_device *cd = &per_cpu(sibyte_hpt_clockevent, cpu);
unsigned char *name = per_cpu(sibyte_hpt_name, cpu);
/* Only have 4 general purpose timers, and we use last one as hpt */ /* Only have 4 general purpose timers, and we use last one as hpt */
BUG_ON(cpu > 2); BUG_ON(cpu > 2);
sprintf(name, "bcm1480-counter %d", cpu);
cd->name = name;
cd->features = CLOCK_EVT_FEAT_PERIODIC |
CLOCK_EVT_MODE_ONESHOT;
clockevent_set_clock(cd, V_SCD_TIMER_FREQ);
cd->max_delta_ns = clockevent_delta2ns(0x7fffff, cd);
cd->min_delta_ns = clockevent_delta2ns(1, cd);
cd->rating = 200;
cd->irq = irq;
cd->cpumask = cpumask_of_cpu(cpu);
cd->set_next_event = sibyte_next_event;
cd->set_mode = sibyte_set_mode;
clockevents_register_device(cd);
sb1250_mask_irq(cpu, irq); sb1250_mask_irq(cpu, irq);
/* Map the timer interrupt to ip[4] of this cpu */ /* Map the timer interrupt to ip[4] of this cpu */
...@@ -165,17 +161,11 @@ void __cpuinit sb1250_clockevent_init(void) ...@@ -165,17 +161,11 @@ void __cpuinit sb1250_clockevent_init(void)
sb1250_unmask_irq(cpu, irq); sb1250_unmask_irq(cpu, irq);
sb1250_steal_irq(irq); sb1250_steal_irq(irq);
/* action->handler = sibyte_counter_handler;
* This interrupt is "special" in that it doesn't use the request_irq action->flags = IRQF_DISABLED | IRQF_PERCPU;
* way to hook the irq line. The timer interrupt is initialized early action->name = name;
* enough to make this a major pain, and it's also firing enough to action->dev_id = cd;
* warrant a bit of special case code. sb1250_timer_interrupt is
* called directly from irq_handler.S when IP[4] is set during an
* interrupt
*/
setup_irq(irq, &sibyte_irqaction); setup_irq(irq, &sibyte_irqaction);
clockevents_register_device(cd);
} }
/* /*
...@@ -195,8 +185,7 @@ struct clocksource bcm1250_clocksource = { ...@@ -195,8 +185,7 @@ struct clocksource bcm1250_clocksource = {
.name = "MIPS", .name = "MIPS",
.rating = 200, .rating = 200,
.read = sb1250_hpt_read, .read = sb1250_hpt_read,
.mask = CLOCKSOURCE_MASK(32), .mask = CLOCKSOURCE_MASK(23),
.shift = 32,
.flags = CLOCK_SOURCE_IS_CONTINUOUS, .flags = CLOCK_SOURCE_IS_CONTINUOUS,
}; };
...@@ -204,6 +193,17 @@ void __init sb1250_clocksource_init(void) ...@@ -204,6 +193,17 @@ void __init sb1250_clocksource_init(void)
{ {
struct clocksource *cs = &bcm1250_clocksource; struct clocksource *cs = &bcm1250_clocksource;
/* Setup hpt using timer #3 but do not enable irq for it */
__raw_writeq(0,
IOADDR(A_SCD_TIMER_REGISTER(SB1250_HPT_NUM,
R_SCD_TIMER_CFG)));
__raw_writeq(SB1250_HPT_VALUE,
IOADDR(A_SCD_TIMER_REGISTER(SB1250_HPT_NUM,
R_SCD_TIMER_INIT)));
__raw_writeq(M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS,
IOADDR(A_SCD_TIMER_REGISTER(SB1250_HPT_NUM,
R_SCD_TIMER_CFG)));
clocksource_set_clock(cs, V_SCD_TIMER_FREQ); clocksource_set_clock(cs, V_SCD_TIMER_FREQ);
clocksource_register(cs); clocksource_register(cs);
} }
......
...@@ -21,6 +21,8 @@ ...@@ -21,6 +21,8 @@
#ifndef _ASM_GT64120_H #ifndef _ASM_GT64120_H
#define _ASM_GT64120_H #define _ASM_GT64120_H
#include <linux/clocksource.h>
#include <asm/addrspace.h> #include <asm/addrspace.h>
#include <asm/byteorder.h> #include <asm/byteorder.h>
...@@ -572,4 +574,7 @@ ...@@ -572,4 +574,7 @@
#define GT_READ(ofs) le32_to_cpu(__GT_READ(ofs)) #define GT_READ(ofs) le32_to_cpu(__GT_READ(ofs))
#define GT_WRITE(ofs, data) __GT_WRITE(ofs, cpu_to_le32(data)) #define GT_WRITE(ofs, data) __GT_WRITE(ofs, cpu_to_le32(data))
extern void gt641xx_set_base_clock(unsigned int clock);
extern int gt641xx_timer0_state(void);
#endif /* _ASM_GT64120_H */ #endif /* _ASM_GT64120_H */
...@@ -2,8 +2,8 @@ ...@@ -2,8 +2,8 @@
* Machine specific IO port address definition for generic. * Machine specific IO port address definition for generic.
* Written by Osamu Tomita <tomita@cinet.co.jp> * Written by Osamu Tomita <tomita@cinet.co.jp>
*/ */
#ifndef _MACH_IO_PORTS_H #ifndef __ASM_I8253_H
#define _MACH_IO_PORTS_H #define __ASM_I8253_H
/* i8253A PIT registers */ /* i8253A PIT registers */
#define PIT_MODE 0x43 #define PIT_MODE 0x43
...@@ -27,4 +27,4 @@ ...@@ -27,4 +27,4 @@
extern void setup_pit_timer(void); extern void setup_pit_timer(void);
#endif /* !_MACH_IO_PORTS_H */ #endif /* __ASM_I8253_H */
...@@ -45,13 +45,11 @@ extern unsigned int soc_type; ...@@ -45,13 +45,11 @@ extern unsigned int soc_type;
extern unsigned int periph_rev; extern unsigned int periph_rev;
extern unsigned int zbbus_mhz; extern unsigned int zbbus_mhz;
extern void sb1250_hpt_setup(void);
extern void sb1250_time_init(void); extern void sb1250_time_init(void);
extern void sb1250_mask_irq(int cpu, int irq); extern void sb1250_mask_irq(int cpu, int irq);
extern void sb1250_unmask_irq(int cpu, int irq); extern void sb1250_unmask_irq(int cpu, int irq);
extern void sb1250_smp_finish(void); extern void sb1250_smp_finish(void);
extern void bcm1480_hpt_setup(void);
extern void bcm1480_time_init(void); extern void bcm1480_time_init(void);
extern void bcm1480_mask_irq(int cpu, int irq); extern void bcm1480_mask_irq(int cpu, int irq);
extern void bcm1480_unmask_irq(int cpu, int irq); extern void bcm1480_unmask_irq(int cpu, int irq);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment