diff options
Diffstat (limited to 'arch/mips/sibyte/bcm1480/time.c')
-rw-r--r-- | arch/mips/sibyte/bcm1480/time.c | 117 |
1 files changed, 50 insertions, 67 deletions
diff --git a/arch/mips/sibyte/bcm1480/time.c b/arch/mips/sibyte/bcm1480/time.c index c730744aa474..610f0253954d 100644 --- a/arch/mips/sibyte/bcm1480/time.c +++ b/arch/mips/sibyte/bcm1480/time.c @@ -15,22 +15,12 @@ * along with this program; if not, write to the Free Software * 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/interrupt.h> +#include <linux/irq.h> #include <linux/percpu.h> #include <linux/spinlock.h> -#include <asm/irq.h> #include <asm/addrspace.h> #include <asm/time.h> #include <asm/io.h> @@ -47,33 +37,10 @@ #define IMR_IP3_VAL K_BCM1480_INT_MAP_I1 #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); -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 */ 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) { case CLOCK_EVT_MODE_PERIODIC: __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, timer_cfg); break; @@ -121,80 +88,96 @@ static int sibyte_next_event(unsigned long delta, struct clock_event_device *cd) return res; } -static DEFINE_PER_CPU(struct clock_event_device, sibyte_hpt_clockevent); - static irqreturn_t sibyte_counter_handler(int irq, void *dev_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 */ __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); return IRQ_HANDLED; } -static struct irqaction sibyte_counter_irqaction = { - .handler = sibyte_counter_handler, - .flags = IRQF_DISABLED | IRQF_PERCPU, - .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); -/* - * 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) { 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 */ - cd->name = "bcm1480-counter"; + 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; - cd->irq = irq; - clockevent_set_clock(cd, BCM1480_HPT_VALUE); + clockevents_register_device(cd); + + 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) { - /* We assume this function is called xtime_lock held. */ - unsigned long count = - __raw_readq(IOADDR(A_SCD_TIMER_REGISTER(0, R_SCD_TIMER_CNT))); - return (jiffies + 1) * (BCM1480_HPT_VALUE / HZ) - count; + return (cycle_t) __raw_readq(IOADDR(A_SCD_ZBBUS_CYCLE_COUNT)); } struct clocksource bcm1480_clocksource = { - .name = "MIPS", + .name = "zbbus-cycles", .rating = 200, .read = bcm1480_hpt_read, - .mask = CLOCKSOURCE_MASK(32), - .shift = 32, + .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; - 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); } -void __init bcm1480_hpt_setup(void) +void __init plat_time_init(void) { - mips_hpt_frequency = BCM1480_HPT_VALUE; sb1480_clocksource_init(); sb1480_clockevent_init(); } |