diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2007-11-01 02:57:55 +0100 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2007-11-02 17:13:47 +0100 |
commit | 217dd11e9d0442767fa13c9c188be0b92dc93d7e (patch) | |
tree | 9557e15fbad397fcc5a707e85cf1a68132ee6c31 | |
parent | [MIPS] Sibyte: Fixes for oneshot timer mode. (diff) | |
download | linux-217dd11e9d0442767fa13c9c188be0b92dc93d7e.tar.xz linux-217dd11e9d0442767fa13c9c188be0b92dc93d7e.zip |
[MIPS] Sibyte: Split and move clock code.
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
-rw-r--r-- | arch/mips/Kconfig | 12 | ||||
-rw-r--r-- | arch/mips/kernel/Makefile | 4 | ||||
-rw-r--r-- | arch/mips/kernel/cevt-bcm1480.c | 149 | ||||
-rw-r--r-- | arch/mips/kernel/cevt-sb1250.c | 148 | ||||
-rw-r--r-- | arch/mips/kernel/csrc-bcm1480.c | 54 | ||||
-rw-r--r-- | arch/mips/kernel/csrc-sb1250.c | 70 | ||||
-rw-r--r-- | arch/mips/sibyte/Kconfig | 14 | ||||
-rw-r--r-- | arch/mips/sibyte/bcm1480/time.c | 160 | ||||
-rw-r--r-- | arch/mips/sibyte/sb1250/time.c | 176 |
9 files changed, 457 insertions, 330 deletions
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 97da953eb5d0..3778c3bbcd28 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -733,15 +733,27 @@ config ARCH_MAY_HAVE_PC_FDC config BOOT_RAW bool +config CEVT_BCM1480 + bool + config CEVT_GT641XX bool config CEVT_R4K bool +config CEVT_SB1250 + bool + config CEVT_TXX9 bool +config CSRC_BCM1480 + bool + +config CSRC_SB1250 + bool + config CFE bool diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile index 3196509a28d5..b551535b7e48 100644 --- a/arch/mips/kernel/Makefile +++ b/arch/mips/kernel/Makefile @@ -8,9 +8,13 @@ obj-y += cpu-probe.o branch.o entry.o genex.o irq.o process.o \ ptrace.o reset.o semaphore.o setup.o signal.o syscall.o \ time.o topology.o traps.o unaligned.o +obj-$(CONFIG_CEVT_BCM1480) += cevt-bcm1480.o obj-$(CONFIG_CEVT_R4K) += cevt-r4k.o obj-$(CONFIG_CEVT_GT641XX) += cevt-gt641xx.o +obj-$(CONFIG_CEVT_SB1250) += cevt-sb1250.o obj-$(CONFIG_CEVT_TXX9) += cevt-txx9.o +obj-$(CONFIG_CSRC_BCM1480) += csrc-bcm1480.o +obj-$(CONFIG_CSRC_SB1250) += csrc-sb1250.o binfmt_irix-objs := irixelf.o irixinv.o irixioctl.o irixsig.o \ irix5sys.o sysirix.o diff --git a/arch/mips/kernel/cevt-bcm1480.c b/arch/mips/kernel/cevt-bcm1480.c new file mode 100644 index 000000000000..21e6d63eb4d1 --- /dev/null +++ b/arch/mips/kernel/cevt-bcm1480.c @@ -0,0 +1,149 @@ +/* + * Copyright (C) 2000,2001,2004 Broadcom Corporation + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +#include <linux/clockchips.h> +#include <linux/interrupt.h> +#include <linux/percpu.h> + +#include <asm/addrspace.h> +#include <asm/io.h> +#include <asm/time.h> + +#include <asm/sibyte/bcm1480_regs.h> +#include <asm/sibyte/sb1250_regs.h> +#include <asm/sibyte/bcm1480_int.h> +#include <asm/sibyte/bcm1480_scd.h> + +#include <asm/sibyte/sb1250.h> + +#define IMR_IP2_VAL K_BCM1480_INT_MAP_I0 +#define IMR_IP3_VAL K_BCM1480_INT_MAP_I1 +#define IMR_IP4_VAL K_BCM1480_INT_MAP_I2 + +/* + * The general purpose timer ticks at 1MHz independent if + * the rest of the system + */ +static void sibyte_set_mode(enum clock_event_mode mode, + struct clock_event_device *evt) +{ + unsigned int cpu = smp_processor_id(); + void __iomem *cfg, *init; + + cfg = IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG)); + init = IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_INIT)); + + switch (mode) { + case CLOCK_EVT_MODE_PERIODIC: + __raw_writeq(0, cfg); + __raw_writeq((V_SCD_TIMER_FREQ / HZ) - 1, init); + __raw_writeq(M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS, + cfg); + break; + + case CLOCK_EVT_MODE_ONESHOT: + /* Stop the timer until we actually program a shot */ + case CLOCK_EVT_MODE_SHUTDOWN: + __raw_writeq(0, cfg); + break; + + case CLOCK_EVT_MODE_UNUSED: /* shuddup gcc */ + case CLOCK_EVT_MODE_RESUME: + ; + } +} + +static int sibyte_next_event(unsigned long delta, struct clock_event_device *cd) +{ + unsigned int cpu = smp_processor_id(); + void __iomem *cfg, *init; + + cfg = IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG)); + init = IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_INIT)); + + __raw_writeq(delta - 1, init); + __raw_writeq(M_SCD_TIMER_ENABLE, cfg); + + return 0; +} + +static irqreturn_t sibyte_counter_handler(int irq, void *dev_id) +{ + unsigned int cpu = smp_processor_id(); + struct clock_event_device *cd = dev_id; + void __iomem *cfg; + unsigned long tmode; + + if (cd->mode == CLOCK_EVT_MODE_PERIODIC) + tmode = M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS; + else + tmode = 0; + + /* ACK interrupt */ + cfg = IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG)); + ____raw_writeq(tmode, cfg); + + cd->event_handler(cd); + + return IRQ_HANDLED; +} + +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 sb1480_clockevent_init(void) +{ + unsigned int cpu = smp_processor_id(); + 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); + unsigned char *name = per_cpu(sibyte_hpt_name, cpu); + + BUG_ON(cpu > 3); /* Only have 4 general purpose timers */ + + sprintf(name, "bcm1480-counter-%d", cpu); + cd->name = name; + cd->features = CLOCK_EVT_FEAT_PERIODIC | + CLOCK_EVT_FEAT_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); + + 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); + + action->handler = sibyte_counter_handler; + action->flags = IRQF_DISABLED | IRQF_PERCPU; + action->name = name; + action->dev_id = cd; + setup_irq(irq, action); +} diff --git a/arch/mips/kernel/cevt-sb1250.c b/arch/mips/kernel/cevt-sb1250.c new file mode 100644 index 000000000000..e2029d0fc39b --- /dev/null +++ b/arch/mips/kernel/cevt-sb1250.c @@ -0,0 +1,148 @@ +/* + * Copyright (C) 2000, 2001 Broadcom Corporation + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +#include <linux/clockchips.h> +#include <linux/interrupt.h> +#include <linux/percpu.h> + +#include <asm/addrspace.h> +#include <asm/io.h> +#include <asm/time.h> + +#include <asm/sibyte/sb1250.h> +#include <asm/sibyte/sb1250_regs.h> +#include <asm/sibyte/sb1250_int.h> +#include <asm/sibyte/sb1250_scd.h> + +#define IMR_IP2_VAL K_INT_MAP_I0 +#define IMR_IP3_VAL K_INT_MAP_I1 +#define IMR_IP4_VAL K_INT_MAP_I2 + +/* + * The general purpose timer ticks at 1MHz independent if + * the rest of the system + */ +static void sibyte_set_mode(enum clock_event_mode mode, + struct clock_event_device *evt) +{ + unsigned int cpu = smp_processor_id(); + void __iomem *cfg, *init; + + cfg = IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG)); + init = IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_INIT)); + + switch (mode) { + case CLOCK_EVT_MODE_PERIODIC: + __raw_writeq(0, cfg); + __raw_writeq((V_SCD_TIMER_FREQ / HZ) - 1, init); + __raw_writeq(M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS, + cfg); + break; + + case CLOCK_EVT_MODE_ONESHOT: + /* Stop the timer until we actually program a shot */ + case CLOCK_EVT_MODE_SHUTDOWN: + __raw_writeq(0, cfg); + break; + + case CLOCK_EVT_MODE_UNUSED: /* shuddup gcc */ + case CLOCK_EVT_MODE_RESUME: + ; + } +} + +static int sibyte_next_event(unsigned long delta, struct clock_event_device *cd) +{ + unsigned int cpu = smp_processor_id(); + void __iomem *cfg, *init; + + cfg = IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG)); + init = IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_INIT)); + + __raw_writeq(delta - 1, init); + __raw_writeq(M_SCD_TIMER_ENABLE, cfg); + + return 0; +} + +static irqreturn_t sibyte_counter_handler(int irq, void *dev_id) +{ + unsigned int cpu = smp_processor_id(); + struct clock_event_device *cd = dev_id; + void __iomem *cfg; + unsigned long tmode; + + if (cd->mode == CLOCK_EVT_MODE_PERIODIC) + tmode = M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS; + else + tmode = 0; + + /* ACK interrupt */ + cfg = IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG)); + ____raw_writeq(tmode, cfg); + + cd->event_handler(cd); + + return IRQ_HANDLED; +} + +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) +{ + unsigned int cpu = smp_processor_id(); + 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 */ + BUG_ON(cpu > 2); + + sprintf(name, "sb1250-counter-%d", cpu); + cd->name = name; + cd->features = CLOCK_EVT_FEAT_PERIODIC | + CLOCK_EVT_FEAT_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); + + /* + * Map the timer interrupt to IP[4] of this cpu + */ + __raw_writeq(IMR_IP4_VAL, + IOADDR(A_IMR_REGISTER(cpu, R_IMR_INTERRUPT_MAP_BASE) + + (irq << 3))); + + sb1250_unmask_irq(cpu, irq); + + action->handler = sibyte_counter_handler; + action->flags = IRQF_DISABLED | IRQF_PERCPU; + action->name = name; + action->dev_id = cd; + setup_irq(irq, action); +} diff --git a/arch/mips/kernel/csrc-bcm1480.c b/arch/mips/kernel/csrc-bcm1480.c new file mode 100644 index 000000000000..868745e7184b --- /dev/null +++ b/arch/mips/kernel/csrc-bcm1480.c @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2000,2001,2004 Broadcom Corporation + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +#include <linux/clocksource.h> + +#include <asm/addrspace.h> +#include <asm/io.h> +#include <asm/time.h> + +#include <asm/sibyte/bcm1480_regs.h> +#include <asm/sibyte/sb1250_regs.h> +#include <asm/sibyte/bcm1480_int.h> +#include <asm/sibyte/bcm1480_scd.h> + +#include <asm/sibyte/sb1250.h> + +static cycle_t bcm1480_hpt_read(void) +{ + return (cycle_t) __raw_readq(IOADDR(A_SCD_ZBBUS_CYCLE_COUNT)); +} + +struct clocksource bcm1480_clocksource = { + .name = "zbbus-cycles", + .rating = 200, + .read = bcm1480_hpt_read, + .mask = CLOCKSOURCE_MASK(64), + .flags = CLOCK_SOURCE_IS_CONTINUOUS, +}; + +void __init sb1480_clocksource_init(void) +{ + struct clocksource *cs = &bcm1480_clocksource; + unsigned int plldiv; + unsigned long zbbus; + + 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); +} diff --git a/arch/mips/kernel/csrc-sb1250.c b/arch/mips/kernel/csrc-sb1250.c new file mode 100644 index 000000000000..ebb16e668877 --- /dev/null +++ b/arch/mips/kernel/csrc-sb1250.c @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2000, 2001 Broadcom Corporation + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +#include <linux/clocksource.h> + +#include <asm/addrspace.h> +#include <asm/io.h> +#include <asm/time.h> + +#include <asm/sibyte/sb1250.h> +#include <asm/sibyte/sb1250_regs.h> +#include <asm/sibyte/sb1250_int.h> +#include <asm/sibyte/sb1250_scd.h> + +#define SB1250_HPT_NUM 3 +#define SB1250_HPT_VALUE M_SCD_TIMER_CNT /* max value */ + +/* + * The HPT is free running from SB1250_HPT_VALUE down to 0 then starts over + * again. + */ +static cycle_t sb1250_hpt_read(void) +{ + unsigned int count; + + count = G_SCD_TIMER_CNT(__raw_readq(IOADDR(A_SCD_TIMER_REGISTER(SB1250_HPT_NUM, R_SCD_TIMER_CNT)))); + + return SB1250_HPT_VALUE - count; +} + +struct clocksource bcm1250_clocksource = { + .name = "MIPS", + .rating = 200, + .read = sb1250_hpt_read, + .mask = CLOCKSOURCE_MASK(23), + .flags = CLOCK_SOURCE_IS_CONTINUOUS, +}; + +void __init sb1250_clocksource_init(void) +{ + 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_register(cs); +} diff --git a/arch/mips/sibyte/Kconfig b/arch/mips/sibyte/Kconfig index e8fb880272bd..366b19d33f77 100644 --- a/arch/mips/sibyte/Kconfig +++ b/arch/mips/sibyte/Kconfig @@ -1,5 +1,7 @@ config SIBYTE_SB1250 bool + select CEVT_SB1250 + select CSRC_SB1250 select HW_HAS_PCI select IRQ_CPU select SIBYTE_ENABLE_LDT_IF_PCI @@ -9,6 +11,8 @@ config SIBYTE_SB1250 config SIBYTE_BCM1120 bool + select CEVT_SB1250 + select CSRC_SB1250 select IRQ_CPU select SIBYTE_BCM112X select SIBYTE_HAS_ZBUS_PROFILING @@ -16,6 +20,8 @@ config SIBYTE_BCM1120 config SIBYTE_BCM1125 bool + select CEVT_SB1250 + select CSRC_SB1250 select HW_HAS_PCI select IRQ_CPU select SIBYTE_BCM112X @@ -24,6 +30,8 @@ config SIBYTE_BCM1125 config SIBYTE_BCM1125H bool + select CEVT_SB1250 + select CSRC_SB1250 select HW_HAS_PCI select IRQ_CPU select SIBYTE_BCM112X @@ -33,12 +41,16 @@ config SIBYTE_BCM1125H config SIBYTE_BCM112X bool + select CEVT_SB1250 + select CSRC_SB1250 select IRQ_CPU select SIBYTE_SB1xxx_SOC select SIBYTE_HAS_ZBUS_PROFILING config SIBYTE_BCM1x80 bool + select CEVT_BCM1480 + select CSRC_BCM1480 select HW_HAS_PCI select IRQ_CPU select SIBYTE_HAS_ZBUS_PROFILING @@ -47,6 +59,8 @@ config SIBYTE_BCM1x80 config SIBYTE_BCM1x55 bool + select CEVT_BCM1480 + select CSRC_BCM1480 select HW_HAS_PCI select IRQ_CPU select SIBYTE_SB1xxx_SOC diff --git a/arch/mips/sibyte/bcm1480/time.c b/arch/mips/sibyte/bcm1480/time.c index 2bcaf5419ac1..1680a68952ae 100644 --- a/arch/mips/sibyte/bcm1480/time.c +++ b/arch/mips/sibyte/bcm1480/time.c @@ -15,164 +15,10 @@ * 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/clockchips.h> -#include <linux/interrupt.h> -#include <linux/percpu.h> +#include <linux/init.h> -#include <asm/addrspace.h> -#include <asm/io.h> -#include <asm/time.h> - -#include <asm/sibyte/bcm1480_regs.h> -#include <asm/sibyte/sb1250_regs.h> -#include <asm/sibyte/bcm1480_int.h> -#include <asm/sibyte/bcm1480_scd.h> - -#include <asm/sibyte/sb1250.h> - - -#define IMR_IP2_VAL K_BCM1480_INT_MAP_I0 -#define IMR_IP3_VAL K_BCM1480_INT_MAP_I1 -#define IMR_IP4_VAL K_BCM1480_INT_MAP_I2 - -/* - * The general purpose timer ticks at 1MHz independent if - * the rest of the system - */ -static void sibyte_set_mode(enum clock_event_mode mode, - struct clock_event_device *evt) -{ - unsigned int cpu = smp_processor_id(); - void __iomem *cfg, *init; - - cfg = IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG)); - init = IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_INIT)); - - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - __raw_writeq(0, cfg); - __raw_writeq((V_SCD_TIMER_FREQ / HZ) - 1, init); - __raw_writeq(M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS, - cfg); - break; - - case CLOCK_EVT_MODE_ONESHOT: - /* Stop the timer until we actually program a shot */ - case CLOCK_EVT_MODE_SHUTDOWN: - __raw_writeq(0, cfg); - break; - - case CLOCK_EVT_MODE_UNUSED: /* shuddup gcc */ - case CLOCK_EVT_MODE_RESUME: - ; - } -} - -static int sibyte_next_event(unsigned long delta, struct clock_event_device *cd) -{ - unsigned int cpu = smp_processor_id(); - void __iomem *cfg, *init; - - cfg = IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG)); - init = IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_INIT)); - - __raw_writeq(delta - 1, init); - __raw_writeq(M_SCD_TIMER_ENABLE, cfg); - - return 0; -} - -static irqreturn_t sibyte_counter_handler(int irq, void *dev_id) -{ - unsigned int cpu = smp_processor_id(); - struct clock_event_device *cd = dev_id; - void __iomem *cfg; - unsigned long tmode; - - if (cd->mode == CLOCK_EVT_MODE_PERIODIC) - tmode = M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS; - else - tmode = 0; - - /* ACK interrupt */ - cfg = IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG)); - ____raw_writeq(tmode, cfg); - - cd->event_handler(cd); - - return IRQ_HANDLED; -} - -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 sb1480_clockevent_init(void) -{ - unsigned int cpu = smp_processor_id(); - 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); - unsigned char *name = per_cpu(sibyte_hpt_name, cpu); - - BUG_ON(cpu > 3); /* Only have 4 general purpose timers */ - - sprintf(name, "bcm1480-counter-%d", cpu); - cd->name = name; - cd->features = CLOCK_EVT_FEAT_PERIODIC | - CLOCK_EVT_FEAT_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); - - 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); - - 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) -{ - return (cycle_t) __raw_readq(IOADDR(A_SCD_ZBBUS_CYCLE_COUNT)); -} - -struct clocksource bcm1480_clocksource = { - .name = "zbbus-cycles", - .rating = 200, - .read = bcm1480_hpt_read, - .mask = CLOCKSOURCE_MASK(64), - .flags = CLOCK_SOURCE_IS_CONTINUOUS, -}; - -void __init sb1480_clocksource_init(void) -{ - struct clocksource *cs = &bcm1480_clocksource; - unsigned int plldiv; - unsigned long zbbus; - - 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); -} +extern void sb1480_clockevent_init(void); +extern void sb1480_clocksource_init(void); void __init plat_time_init(void) { diff --git a/arch/mips/sibyte/sb1250/time.c b/arch/mips/sibyte/sb1250/time.c index 24b9c8bad62f..68337bf7a5aa 100644 --- a/arch/mips/sibyte/sb1250/time.c +++ b/arch/mips/sibyte/sb1250/time.c @@ -15,180 +15,10 @@ * 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/clockchips.h> -#include <linux/interrupt.h> -#include <linux/percpu.h> +#include <linux/init.h> -#include <asm/addrspace.h> -#include <asm/io.h> -#include <asm/time.h> - -#include <asm/sibyte/sb1250.h> -#include <asm/sibyte/sb1250_regs.h> -#include <asm/sibyte/sb1250_int.h> -#include <asm/sibyte/sb1250_scd.h> - -#define IMR_IP2_VAL K_INT_MAP_I0 -#define IMR_IP3_VAL K_INT_MAP_I1 -#define IMR_IP4_VAL K_INT_MAP_I2 - -#define SB1250_HPT_NUM 3 -#define SB1250_HPT_VALUE M_SCD_TIMER_CNT /* max value */ - -/* - * The general purpose timer ticks at 1MHz independent if - * the rest of the system - */ -static void sibyte_set_mode(enum clock_event_mode mode, - struct clock_event_device *evt) -{ - unsigned int cpu = smp_processor_id(); - void __iomem *cfg, *init; - - cfg = IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG)); - init = IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_INIT)); - - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - __raw_writeq(0, cfg); - __raw_writeq((V_SCD_TIMER_FREQ / HZ) - 1, init); - __raw_writeq(M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS, - cfg); - break; - - case CLOCK_EVT_MODE_ONESHOT: - /* Stop the timer until we actually program a shot */ - case CLOCK_EVT_MODE_SHUTDOWN: - __raw_writeq(0, cfg); - break; - - case CLOCK_EVT_MODE_UNUSED: /* shuddup gcc */ - case CLOCK_EVT_MODE_RESUME: - ; - } -} - -static int sibyte_next_event(unsigned long delta, struct clock_event_device *cd) -{ - unsigned int cpu = smp_processor_id(); - void __iomem *cfg, *init; - - cfg = IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG)); - init = IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_INIT)); - - __raw_writeq(delta - 1, init); - __raw_writeq(M_SCD_TIMER_ENABLE, cfg); - - return 0; -} - -static irqreturn_t sibyte_counter_handler(int irq, void *dev_id) -{ - unsigned int cpu = smp_processor_id(); - struct clock_event_device *cd = dev_id; - void __iomem *cfg; - unsigned long tmode; - - if (cd->mode == CLOCK_EVT_MODE_PERIODIC) - tmode = M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS; - else - tmode = 0; - - /* ACK interrupt */ - cfg = IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG)); - ____raw_writeq(tmode, cfg); - - cd->event_handler(cd); - - return IRQ_HANDLED; -} - -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) -{ - unsigned int cpu = smp_processor_id(); - 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 */ - BUG_ON(cpu > 2); - - sprintf(name, "sb1250-counter-%d", cpu); - cd->name = name; - cd->features = CLOCK_EVT_FEAT_PERIODIC | - CLOCK_EVT_FEAT_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); - - /* - * Map the timer interrupt to IP[4] of this cpu - */ - __raw_writeq(IMR_IP4_VAL, - IOADDR(A_IMR_REGISTER(cpu, R_IMR_INTERRUPT_MAP_BASE) + - (irq << 3))); - - sb1250_unmask_irq(cpu, irq); - - action->handler = sibyte_counter_handler; - action->flags = IRQF_DISABLED | IRQF_PERCPU; - action->name = name; - action->dev_id = cd; - setup_irq(irq, action); -} - -/* - * The HPT is free running from SB1250_HPT_VALUE down to 0 then starts over - * again. - */ -static cycle_t sb1250_hpt_read(void) -{ - unsigned int count; - - count = G_SCD_TIMER_CNT(__raw_readq(IOADDR(A_SCD_TIMER_REGISTER(SB1250_HPT_NUM, R_SCD_TIMER_CNT)))); - - return SB1250_HPT_VALUE - count; -} - -struct clocksource bcm1250_clocksource = { - .name = "MIPS", - .rating = 200, - .read = sb1250_hpt_read, - .mask = CLOCKSOURCE_MASK(23), - .flags = CLOCK_SOURCE_IS_CONTINUOUS, -}; - -void __init sb1250_clocksource_init(void) -{ - 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_register(cs); -} +extern void sb1250_clocksource_init(void); +extern void sb1250_clockevent_init(void); void __init plat_time_init(void) { |